 for a C sharp code into functional style. Best time to ask questions or make comments is when you have it, so please don't wait till the end. Any time is a great time. So I want to talk about just a little bit and then get into some code examples after that. What do we really get out of functional style? So a couple of things very high level to highlight. One is declarative, meaning the code you're writing is really telling you what to do rather than focusing on how to do it. You let the underlying libraries decide how to do things. You're using higher order functions, meaning you can pass functions to functions, receive function from functions as well. You honor immutability. We talked about this during a few sessions. So you are trying to prevent immutability as much as you can. You are honoring immutability, which takes a little bit getting used to, but that's a better way of programming because there are fewer moving parts in it. And you also honor pure functions. Pure functions are functions with no side effect. You're not trying to mutate state. While the function is running, you're not modifying something outside. While the function is running, something outside doesn't affect the outcome of the function also. But why do all of this? First, the code is more concise. I want to distinguish between the two terms, concise and terse. A terse code is short, but waiting to hurt you. Concise code is short and transparent. So we want concise code, not terse code. And usually this code ends up being very concise. It's very expressive. So it's very easy to read the code and understand, communicate your intent much more easily. We usually end up writing a lot less code. And as a result, it's easier to understand because of the expressiveness. Once we get used to the syntax, it's easy to modify the code because of the way it's structured. The code begins to read like the problem statement. We end up having fewer bugs in the code as well because of fewer moving parts in it. And almost effortless to paralyze and make it efficient as well. With all that said, it's really a paradigm shift in terms of how we used to code to where, how we want to code. So I want to start with some examples to work with it. The first is about iterating. One of the reasons I want to talk about this is I work with quite a number of clients who also use C-sharp. And when I start working with them, one thing I noticed quite often is they still continue to write code the way they used to using the traditional for loops. And they haven't quite made the transition even though C-sharp has had functional style of programming a Lambda expression for a number of years now. So let's talk about iterating just for a minute with a little example here. So what do I have on my hand in this case? Notice I have a little C-sharp code. And the code has a list. And I'm looping through the list one element at a time and I'm printing it. That is all I'm doing here. So this is a very familiar code, right? So you have a list of values, the four i equal to zero, i less than the count, i plus plus, and then you print the value. Now this is called an external iterator. And an external iterator is where you control the iteration all by yourself. Now there's a good news about this iteration. Normally people say this is a simple iteration. But I wanna say the word is not simple, the word is familiar. There's a very big difference between the two. Not everything that's familiar actually is simple. Something that is familiar is something we have kind of accepted even though it may be really complex. In fact, I would argue this code is complex because it's got way too many moving parts in it. Now take a look at an example here. I'm gonna say for each and I'm gonna say element in numbers. And I wanna output the element. Now notice these two code for a second. You can no longer claim this is simple because we simply saw another one that's simpler than the other one, right? Now why is the code on line number 19 simpler than the one in line 15? And the reason for that is the one on 19 has fewer moving parts. You are not initializing a variable. You're not setting a boundary condition on it. You simply said for each of the elements do this. Both of them are external iterators. However, the second one is simpler than the first one. We could have done either one of them and she sure has had both of those for a very long time. However, we would much rather do internal iteration rather than external iteration. So notice rather than that about two, we could rewrite this. We could say for example numbers and then we could say for each. And we could start using the internal iterator on this and we are saying for each of the values in this collection, I wanna perform an operation. So given an element, I wanna output the element in this case. So we are trading our external iterator to an internal iterator in this particular case. Now if you look at this particular code, the idea behind this code is you are rather than controlling the external iteration, you are relying on a polymorphic behavior. Now what is polymorphic in this case? You're calling the for each on the collection which means the iteration could be sequential, the iteration could be concurrent, the iteration could be lazy. Whatever those options are, you can gain from those because as we know polymorphism, go ahead and call a method on an object but the real implementation is postponed to run time rather than being decided ahead of time. So this gives you that flexibility to pick and choose the implementation at a later time. This could be a collection, could be a parallel collection, what have you. That benefit comes to you when you start using this kind of behavior. The code is also concise as you can see, expressiveness of course, we gotta get familiar with the syntax but it's expressive because you're saying given this particular collection, I wanna do some operations with that collection, that's what you're expressing. So the idea really is that you are getting to the values very effectively to iterate over them. So in this case of course, I am asking you to iterate through the values and perform the operation on the values in this collection. So the idea behind this is it's an internal iterate. So what does an internal iterator really mean? The internal iterator means that I'm gonna send a function. This is a function that we are trying to send. So I'm saying for each and I'm making a mistake here, I'll figure out what it is in a second. So I'm saying for each of the methods, I wanna pass in a function as a parameter. So notice rather than saying do the looping and do this work, you are asking it to do the work but you're sending the unit of work as a function. So given an element, I wanna go ahead and print the value of the element, that's what you're commanding in this particular case. So that becomes a very natural way to express once you get used to the syntax, please. Right, so in the case of ordering, by default, this is a sequential collection. So the iteration is gonna be sequential. In the case of printing out, you're absolutely right, the ordering does matter. But in a lot of other cases, the ordering doesn't matter, right? So you need to pick and choose when it doesn't, when it doesn't. The for each itself is going to be a simple sequential iteration for most part, so it wouldn't be a problem for it. But on the other hand, if I'm doing some mapping operations, let's say for a minute. Well, if I'm performing a mapping operation, I can certainly do maps more concurrently rather than doing it sequentially, right? So you gotta pick and choose when it makes sense to perform one operation versus another, and that is pretty much domain and context dependent. You can't really make a claim one way or the other. You gotta make a decision based on what you're trying to really do, and that's basically what you have to pick and choose. So the idea really is that you wanna really make a choice based on what you're trying to do, basically based on the domain that you are working with. I'm not sure exactly why this guy, oh, I know why the problem was. I need to include import over here, that's the reason for it. I actually have a generic import, so I'm not sure exactly what the error was. Let me see what the error says over here. Okay, so I had a mistake here that I couldn't recognize what the error was. Anyway, so you can see the iteration works just fine by providing, that's the lambda that you're passing to this function for it to exist. Okay, now let's go a step further. What if I want to perform a filtering operation? What does that really mean? Let's take an example for this to understand how the filtering is gonna work, and then we can compare and contrast it. So let's look at the old style of coding first of all. I got a collection of values, and what am I doing with this collection? With this collection, I first set filtered and I created an empty collection as you can see here. Then I loop through one element at a time, and for every element, I check if it is even, and if it is, I add it to the filtered collection. Then I loop through again and print the values. Again, you can see the imperative style of coding right here. Now, if I run this code, we can see that in this case, we only printed even values from the collection. So that isn't again an imperative style of coding, but as we get used to the code, we elevate ourselves to more of a declarative nature. Let's see how that's gonna feel like. So I've got numbers, but what am I interested in doing here? Given this collection, look at what this code was doing at a very primitive level. It loops through one element at a time, checks if a value is even, and if it is, it adds to another collection. In other words, this is really a filter operation. So what I can do is I can say, given these numbers where, so where is an operation I perform, and normally in functional programming, we call this a filter operation. Well, in C sharp, they didn't call it a filter. Would have been nice if they did, but they call it a where instance. So this is kind of like saying, given these values, only do this operation where this predicate applies, right? That's what you're trying to do here. So where, given an element, you can say element mod two is equal to zero. So you're specifying what kind of operation you wanna perform on that. So this is gonna give you only the values that are meeting that criteria. Then you can say for each, and for each of the values, what do you wanna do? Given the element, I wanna go ahead and print the element out from that particular result. That's what you're trying to do as an output operation, right? That's what the for each is doing here. So the idea behind this is, a where operation simply says, select these values, and for these values that are selected, you know, give me a result, a collection, and I could loop through and print the values, whatever that I wanna do, I could perform at that particular operation. So the idea behind this is simply to bring in the operations, and of course, because, okay, there's another small detail. The for each is only available on a concrete collection, unfortunately. This is a bit of a let down, in my opinion. So as a result, you have to escalate that to, or down, bring it to a list object. So to say, I wanna iterate on the list and print it. Would be nice if you don't have to come to a list and still continue with the operation further. That would have been really nice to work with. So the where operation does the filtering operation for us, and then you can bring down the filtered operation. I'm gonna bring the code here with the error that's displaying. So where, again, the operation that we performed here, do list, and then for each, and I'm performing that operation and printing the result, and getting the output. So notice the difference between the code again. You're not at the low level of operation. Instead, you elevate it to a higher level and you're flowing through. This is a function composition or transformation you're looking at. So numbers where that criteria is met, put the result into a list, and then from the list, go ahead and loop through and get the results to me. So what's the model of the story? We should really deprecate or expire the traditional foreign moves and go more towards internal iterators as much as possible. Now, what's the biggest difference in doing so? The first difference is we are going from an imperative style to a declarative style. So in the case of imperative style, we specify every single step of not only what to do, but how to do it. Think about the code we had a minute ago. Go through each one element. Take one element. Check if it is even. If it is even, then add it to this list. Notice how you're focused on every single low-level step. In the case of declarative style, you focus more on the high-level step. You say, here's a collection. Perform this operation where elements meet this criteria. So you're focusing more on the whole rather than each and every single value. You are focused on how, in the case of imperative, you're more focused on what in the case of declarative. You say what to do rather than how to do it and you let the underlying library functions take care of it. You are dealing with mutability versus immutability. If you recollect the old code, what did we do? We loop through and we said add, add, add. Well, add is a mutable operation. You take a list and you keep poking at it and you're adding elements to it. And obviously, that's very difficult to make concurrent as well. In this case, you don't have any mutability at all. In fact, you just ask it to do the work and you tell them, give me a result, a resulting list. So you're not in the business of creating a list. You are in the business of telling what to do and it gives you a result of a list as in response. So you avoid explicit mutability in this code. You have side effect versus pure functions. What is the side effect in the other code? Well, the mutability certainly is a side effect. You're sitting there and constantly modifying the collection, whereas in here, you are not really mutating anything at least explicitly. Mutability may happen under the hood, but your code is not doing any mutation. So you're focusing on pure functions. You accept data and objects in imperative code, whereas here you are accepting functions as well. Notice in this code how you are able to receive a function as a parameter rather than just passing objects alone. So that is where the where is a higher order function because you're passing a function to this function rather than passing objects alone. So you're doing function composition rather than object composition alone. So that gives you the benefit of putting together this function composition. In the case of functional style, imperative style, it's hard to compose. Remember the for loop that you had? What do we call this? We call it a for statement. You do one for, you get the result, then you come back to do another for and another for. So if you notice the code we had, we got two for loops. You could merge them into one, but that's trying to do too many things in one place which only makes the code more complex. Whereas here, you got a nice function composition. Operation one, the result of which flows into operation two, the result of which flows into operation three and you are transforming this code, the data nicely. That's function composition at work. And rather than mutating data, you are transforming data. So it feels more natural to say, this is the current state, this is the new state rather than saying this is the current state and I just polluted it with the new state, the old state is gone, right? So you're preserving the value that you had and you are making a copy of it. Now of course you may say copying is inefficient, well it doesn't have to be inefficient. That's where the smartness of the libraries and the language comes in and we'll talk about how the efficiency is not compromised in just a few minutes. Now let's look at one more example. I want to double values let's say in this particular case. How do I double the values? Well for doubling the values what I'm gonna do is let's take one other example and work with it. So this is called doubling the values and again look at the low level code. I got a collection of values. Then I take the list, I loop through every single element and I double the value and then I add it to the list. Again notice the symptom of imperative, mutability at work, specifying things at a low level per element. Then we loop through and print the values. But this is doubling the values. What can we do to avoid this? So notice what I'm gonna do here. Numbers start, well in this case we are not filtering any values, right? So this is a transformation where we wanna take a collection of values but we wanna produce another collection where every element in the resulting collection is a double of the values in the input collection. So for this we use a select method. In functional programming we normally call this map. I wish they had called it map here as well but they called it select. So what does select do? Select says given an element return whatever that may make sense. In this case I wanna return double of those values, right? So this is essentially a mapping operation. Again notice how you focus at the high level rather than the low level of this object. So then I can say for example a two list and then I can say for each and I can specify what the value is and I just realized what my problem was. I was typing a lower case F and that's what happens when you program in two many different languages your brain doesn't switch over it's gotta be uppercase and C sharp, there we go. So E is the element, what do I do here? And I wanna print the value out here, right? So that's what I'm trying to do at this point. So the main idea behind this is compare the code up here to the code below, right? Concise, high level, expressive to the point and it feels like you're speaking to an adult rather than a toddler, right? So at the highlighted code you are sitting there and babysitting through every single step. Whereas here you're saying given this collect perform this mapping, give me a list and print the value, right? So it begins to read more natural once you get used to it compared to the previous code. Now think about this for a second. If you are looking at the top code and somebody comes to you and says take the highlighted code and make it multi-threaded because this operation is too slow I wanna make it faster. The short answer is tough work, right? In the bottom code I don't have to do much work at all because I could use a parallel collection and the select can go concurrently. I don't have to expend any effort. Structurally the code is gonna be exactly the same so that has a very big benefit as you can see, please. Sure, why? I want to multiply by some number. So let's take an example here. Yeah. Just as an example let's say even numbers I wanna double, odd numbers I wanna triple. Yeah, something like that. So notice the beauty here. In the code about what would we do? We would say if element is even, then you would say double dot add and then you would say, for example, E times two and then you would say else E times three. Well, we could probably make that a little bit better by storing the result temporarily. You could say int result equals and then you would specify this as a result over here, you get the point, right? And then you would do add once. But in a sense, if you really look at it, you have kind of lost sight of what you're really doing. Why? Because you gotta step into the code and you gotta examine that and say, what are you really doing? And then you're like, oh, I got it, right? In other words, this fails a very important principle called slap. It stands for single level of abstraction principle. Single level of abstraction principle says when you have a code, the code should focus on one level of abstraction. And if you look at this code, this is all over the map. Everything happens here, right? There is absolute disregard to abstraction, right? Oh, I've got to loop. I've got to work with the collection. I've got to, now, all of a sudden, I'm making a low level decision. I've got to make a comparison, right? So look at what we lost in it, right? We got everything going on in one place. Instead, let's go ahead and go to this code in the bottom and let's just go ahead and say, just as an example in this class, let's say static int. Let's give it a name, right? Whatever that operation you could, we'll call it as transform, well, let's say double or triple, whatever you want to call it, right? Based on your domain, it's going to have some logical meaning. And then you could say int number, and then what would you do here? You could simply do something like number, well, return, of course, and you could say number mod two is equal to zero. If it's even, then return number times two, otherwise return number times three, right? Whatever that may be, the logic, you can implement it separately. Now that is a low level detail, would you agree? That's why it's a slap, right? You isolated that into a separate method because that's where that logic belongs. Then you say double or triple, and I will simply come up here and I would say double or triple, right? So then you are saying, hey, you know what, at my level, I don't care about the low level detail, I'm transforming stuff, that's all I do, right? So this says select double or triple, meaning map that on that operation, then convert to a list and do my work. Then the low level detail, see how this promotes doing the right thing. So that is one thing we need to keep in mind, right? A language should promote good behavior, imperative code promotes more bad behavior, right? It is inviting you to do more bad stuff, right? Whereas here, it's like, you know what? If I put a massive if-else condition here, that's gonna get very stinky very quickly. And then you're gonna look at this and say, well, I don't think I should be doing that. That clearly is not the right thing to do. Now we follow the slap principle, right? A single level of abstraction principle, and we moved it down. So that is another nice thing, is the language should provide us the right behavior, as you can see, right? Really good question. So notice how we moved this down, and then we can say, you know, even things are doubled and odd things are tripled, or whatever that logic is, that's where it belongs. And so we also applied a slap, single level of abstraction principle, which is a better, better healthy coding anyways. We'll explain it. Thank you. Absolutely, really good question. So that is an example of how we can go towards that. Well, this also leads us to being lazy. And the point about being lazy, this is a great example to look at it. Notice in this example, I have done this operation here, but this operation of select is happening right here. Let's go ahead and just output for our purpose. Let's say, you know, done. You could notice in this case, I could go back and write this just to show that this is being called, called for, let's say, number. So if I run this, you can see those are called for each of those numbers, right, makes with sense. But the beauty is this. These methods are, they are very deceiving in a way. When you look at them, you don't see this. It appears like they're here towards poor performance, but they really are not. Because if you look at this collection, we are saying select, meaning map on these, then convert to a list and then do this operation. Let's say we don't care to convert to print right now. We'll just keep it as a to list for a second. And when I run this, you can see those things are being done also. But if I go back and remove that part also for a second, did you notice no work was extended, right? This is like, I was mentioning this earlier, this is like some people at work. They come to work, look around, the boss is not at work, hey, great. I don't have to do any work today, right? So these guys are lazy to the bone. So even though you call select, the select says, I don't have to really do any work because my result is not used, so why bother doing the work, right? So we talked about earlier in the Haskell session, if you were there, we talked about how these functions can be lazy. That's exactly what you see here, right? So you don't give the result of an evaluation, you give a function to evaluate. And the select says, and later, I don't have to do this now, right? So it postpones it. And how long does it postpone? You could do another, right? So you could say dot where, and what do we wanna do? Given an element, I could say element is greater than five, for example. So notice in this case, still no work was extended. So all that work that could have been done was never done. And then you say, now I wanna convert this to a list, only now it is doing the work, not otherwise, right? So in other words, these are terminal operations, and terminal operations don't take effect, I'm sorry, intermediate operations are these. Intermediate operations don't take any effect until terminal operations kick in. So this is laziness baked in. And laziness automatically gives you efficiency and code. If we had written this code through the imperative style, we have to work hard to get that kind of efficiency, right? Because our code is eager all the time. But there's benefit to being lazy. What's the benefit to being lazy? Well, if I don't ever have to do this, then avoid it doing the work, right? And if you avoid doing the real work, then you're more scalable, because then you spend more effort doing real work that you need to do, rather than spinning the wheel doing stuff that is of no consequence anyway. So you can see that laziness is already built into the language. Where is lazy? Select is lazy already. And there are these functions that are absolutely lazy already, and all we have to do is just use them. So there is another benefit to using these, instead of using the looping as we saw before, because we got the laziness baked into it. This is something that really fascinated me, called the tell don't ask. We all write code like this all the time, and we tend to forget about some nice principles. And thanks to you, we talked about one extra principle, which is the slap principle. But one other principle in good object-oriented design, or good design in general, is called the tell don't ask principle. The tell don't ask principle says, do not go to an object, perform a query on it, then make a decision, and then go back and affect its state, right? We tend to do this quite a bit. You go to an object and say, hey, how old are you, for example, not you specifically, but how old are you? And you find out what the age of the person is, then you make decision for them, and then you go back and say here, you can have this or you cannot have this. Well, rather than that, you instead simply tell the person, you know what, here you go, do this if you are eligible to do, right? Then your code becomes a lot simpler, and b, the function you, the code you are calling, can evolve polymorphically. Tomorrow, you have to decide, let's say for example, let's take an example, right? Let's say age has to do with something, maybe the voting loss. Let's say, hey, if you are less than 18, you cannot vote. Well, who makes the decision? I'm gonna make the decision. I'm gonna ask you, how old are you? And then based on that, I'm gonna make a decision. Well, imagine there's a state law change, and one state which is agreed to get more votes decides. People who are older than 16 can vote in that state. What's gonna happen to the code now? Your code is dead in the water, right? Because now your code has to say, well, if you are in this age, and if you live in this state, then, and that is gonna become a mess to deal with. Instead you say, hey, person, vote if you can. Well, the person decides whether the person can vote or not. Well, tomorrow, the state law changes. Well, the person living in the state evolves with it. Your code is still intact, it's extensible, right? So extensibility is attained by removing responsibility and placing it exactly where it belongs. I'll give you one example which I ran into which was quite fascinating to think about because sometimes we do this and don't realize it. So let's look at an example of, I call this the ask example, and let's take this example to see what it feels like. I've got a class called room, and the room class contains a Boolean field to say whether the room is booked. I've got a constructor that tells me whether the room is booked on create. I've got a ease available method that returns to me whether the room is available or not. And then I have a book method which is going to take a date and perform a booking operation, right? So notice the way this code is structured, it's structured for the ask rather than tell, right? So you would first go to the object and say, are you available? It says yes or no. Then you go perform a book operation on it to say, I want to book you now because you're available. Now there's another inherent problem in this code. By the time you ask it if it's booked, to the time you come back to book it, it probably is taken already. That's more fun for you to deal with, right? So this is again going back to what we talked about in your previous question, right? We impose this complexity, right? We deserve punishment for this because this is accidental complexity we introduced on ourselves. That is the room class. Now it's even worse. Look at this code now, what does it do? This code says I got a bunch of rooms on my hand. I'm gonna first say room is null, right? What is null? The way you pronounce null is smell, right? That's what it really is. It's very smelly. So you got a null variable on your hand. Then you'll loop through every single room. You ask if a room is available. If the room is available, you book it and then you set this variable to the room and then you break out of it. Notice a very primitive set of code that we are using here. And once we do, then we print what the booked room is. There's another problem here. It is quite likely that the book room is actually null at this point because all the rooms were taken, oops, sorry, all the rooms were taken and as a result, we ended up with no room and we have to deal with it. So that is the consequence of this code. But how can we get around it? Well, I was actually working on something when we wrote a little unit test, we wrote this code and I looked at this and I stared at it and said, okay, something doesn't feel right here. This test passes, the code is there, but you have sometimes that feeling, right? You know something is wrong, but you don't know what's wrong. There's a little gut feeling that something is smelly but you can't put your finger on it. So we're working with this and we wrote this code and left a little unhappiness. What is the problem in this code? And after a few minutes of thinking, it jumped on as like, ah, I get it. It's a failure of tell, don't ask principle because we are querying the object, making a decision and then going back and setting things. So rather than doing this, what we could do is we could rewrite the room. So what we can say here is rather than ease available and do this, how about the following? We could simply say public void, book if available, right? So one shot, book if it's available and we're gonna specify the date and time, whatever that information it needs, date. So we can pretty much make these methods as private methods for now. These are not accessible anymore. And then we could simply say in this case, we could say if, well, first of all, we could say available equals ease available for, ease available for date, right? So first we check, well, if it is available, we still have to say whether we got it or not. So if it's available, what do we do? We can simply say book on that date, right? So book on that particular date. So we could simply say date and return the availability, right? So this will tell you whether you were able to get it or not. So book is available. Well, if it's not available, don't book it, right? It's gonna be false. If it was available, then go ahead and book it and return it, true for me. So we converted this into a one function called delegating the responsibility. What is the benefit? Tomorrow, the logic on booking changes. There's a special rule. Some rooms cannot be booked even if it's available if it is a certain period of time. You know, maybe a high season, whatever it is, right? Well, where does that logic go? It rightfully goes right here. But in the previous case, we'd be polluting the code with that logic where it doesn't belong, right? So that is basically the difference in this case, we wrote this method. But then what we do is, remember that laziness we talked about? Well, we can leverage the laziness very nicely. So what we're gonna do for that is, we got a list of rooms. So rooms dot, and we can simply say in this case, where. So once again, we are applying a filter operation for this guy. So we say where, and what do we wanna perform in the where? Well, given a room, we're gonna tell him room dot book if available, right? And then we're gonna specify the date that we are interested in. So what is that particular date we are interested in? Well, date dot now, so we could simply say date equals date dot now. So we are asking it for that specific date. Well, this is a filter operation, so what does it do? It gives you all the date rooms that are available. But no, we don't want to book all the rooms. We only wanna book one room, right? Whichever is the first room that's available, that's all we are interested in, not book all the rooms. So we could then take that, and we could ask for the first one to be available. Now when you look at this, it is not intuitive until unless you know about the laziness of functional programming, right? So when you say do thousand things, but get me the first one, it won't do thousand things and get you the first one. It'll only do the first thing and get you that. This is especially important from the point of view of infinite and lazy collection, because you don't even know how far this is, but you ask it to do only minimum work to get the result for you. So if you look at that code, compared to the code you have in the bottom, notice how we went from again an imperative style and failure of the tell-don't-ask to simply saying, hey I tell you to book and get me the first one, whichever is available, right? So you can bypass a lot of work and focus on applying these kinds of principles. It takes a bit of effort to rethink about it, but to me the best design tool ever in my opinion is how do you feel? To me that is one thing I always listen to. I would write a piece of code and I would be walking around and I would tell myself, I am not happy with this code. Sometimes the kids come over to me and say, Daddy are you really angry right now? He's like, no it's not you kid, it's the code that's making me angry, right? So you gotta feel that anger in you, right? I wrote that code, it stinks, I'm not happy with it. And then in a matter of minutes you will refactor it and find a better way to do this and that can be pretty helpful to rewrite the code in a better way and that can help us a lot in getting the things done very differently. So let's go back and look at this example real quick. This is gonna be the book to room that we are interested in and I could save that away into book to room. So we could save for example room and that's gonna be the book room equals and we can store that away into the room. So the idea really is we are again using a very, very high level of code. So did you notice what he did? He did checking, checking, checking, room booked and then he gives you a room but how many do we have? I have one, two, three, four but it checked the first and the second. They both are booked already. Then it checked the third which is the first one that's available but notice it never checked the fourth one because the third one was available, it booked it, right? So that's why the where doesn't run all the way through the where runs only until it pleases the first, right? The where works for the first. It's extremely lazy, right? It's like, hey, you wanna report? Here, are you happy with it? Yes, I don't have to write anymore, right? So you're just working for just to serve the terminal, the laziness takes effect. So the code becomes very expressive as you can see because of that in this particular case. So what we saw here is a very systematic imperative functional rather than being low level at element level, be at a high level at the collection level, right? And we leverage lazy quite a few times, right? So we are saying, well, here is an operation but I can postpone the operation until I really have to execute it and you can see how the laziness comes into play here by writing the code in a very highly elegant way by simply saying, go ahead and do this for me at this level and get me the first element. So the laziness, without laziness, this code would be incorrect as far as the logic is concerned, right? Because poor thing, this would book all the rooms and get you the first one, which is complete nonsense. We don't want to do that, whereas the laziness comes to help here. It only books the first available room and gives you that value, right? Of course, you can't make this quite parallel because it may end up booking multiple rooms. So going back to the earlier question you asked, we got to be careful whether to make it parallel or not. We got to know the logic, right? Oh, no, it is hard to reason because of unfamiliarity. That is something to keep in mind, right? When you are unfamiliar with something, it is hard to reason. That is why I keep saying several times once you get comfortable with functional style, right? So when you start working with functional style, your eyes should start looking at laziness. But remember the very first time you looked at polymorphism and said this is gonna be hard to reason, right? Because what does polymorphism do? You call a method here, it ends up over there. It's like how cool that is. And there are people scratching their hands is that really cool? That can be hard to understand, hard to debug, hard to work, right? Same similar concept. So once you're familiar, your mind thinks along those lines, then it becomes easier to reason. It's like, oh, I got this collection, I applied this operation, get this result. It becomes easier to express that. But again, you have to know when it makes sense to parallelize and when not to parallelize. A lot of times parallelization is useful when you have optimization problems. You don't care which results you get but you want one of the results that would make sense. Whereas in these kinds of cases, you gotta be very careful which one you are really getting as a result. You gotta be very careful about that too. There's also one small consequence in this code which is this code actually has a side effect, right? Because you are modifying the room and so in effect you are mutating it, which is really something you gotta be very careful about because you're altering that. So an alternate may be to return a copy of the book to room and the original rooms are left intact so you can work through that to avoid the kind of mutability if you want to. But that's basically the idea is systematically going from imperative to declarative and functional, avoiding for loops, trading internally to raters and working with these higher order functions and then thinking about formulating the problem in a way it becomes more expressive. So fewer lines of code which is more expressive is better than a code that is convoluted and then of course we also saw how the single response of the principle the single level of abstraction principle all that is much more expressed beautifully here compared to in the imperial style of coding, right? So I hope you found that useful. That's all I have. Thank you.