 Is that good? All right, well, first of all, thank you so much for taking the time to join here. It's a great pleasure to have you all. Thank you so much for the facility and for all the effort to organize. So I want to talk about something that we struggled quite a bit, which is how do we write code in functional style? So I want to spend just a few minutes talking about the context, and then we'll dive in and talk about refactoring through functional style after that. The best time to ask questions or make comments is anytime you have a question or a comment. So please don't hesitate. Anytime is a great time. Just draw my attention, start speaking. I'll be delighted to listen to what you have to say. So we all have been programming in imperative style. I would say that's probably what most of us are familiar with, unless you took some weird course in colleges and they forced you to do functional programming. We pretty much did that. And for my experience, for my most part, I've done imperative style of programming. I spent my youth writing code in imperative style. I spent my youth writing code in C++. What I'm telling you in so many words is I had a very dark past. And eventually, of course, I stumbled upon functional programming. And one of the things that made it really hard for me to transition was that people who knew functional programming often said, oh, it's really easy, but it was not. And part of the reason it's really hard is we can learn syntax fairly easily. We are good at doing it. We can learn libraries really easily. But what's really, really hard for us programmers is the paradigm shift. Because paradigm shift doesn't require us to just learn something extra. Paradigm shift requires that we change our thinking. Thinking is hard in the first place. And changing the thinking is even more difficult. So that transitioning was really hard for me to start programming in functional style. And honestly, I would say I'm not really good at it. But I'm not good at anything for that matter. But it gets better over time with more practice. And that's what I want to focus on today is how can we get better at writing functional style code. But before we do that, let's set some context here. What does it really mean to program functional, program imperative? What does all that mean? So let's take a little example and play with it to get a feel for this so we can see what that really may mean in this particular context. So let's say we have a collection of names. I'll say names is equal to. Let's say a list of, in this case, we'll say some names that I want to start with. As you can see, I typed really fast. And in here, I want to be able to find out if our good friend Nemo is in this collection. So how do you find if Nemo is this collection? We, every one of us, have written code like this, isn't it? So what we can do here is we can say, first of all, we can say Boolean and we can say found is equal to false. Then of course, if found is true, we can maybe print out something beautiful. We can say Nemo found. Maybe play a nice little music to celebrate it. Or we can simply say, in this particular case, we could print a message. In this case, we could say maybe Nemo not found. And then we can play maybe a sad music. But within this, what do we do? We can say for i equal to 0. And then i less than and then, oh, is it less than or less than or equal to? How many times have we asked that question? So when people ask me, what is that symbol? I say that's an international symbol for I feel stupid. Because every time you write it, you got to pass and say, hm, is it boundary condition less than or equal to? And you're never sure about it, right? You walk away and you're still thinking. Is it less than or less than or equal to? We have to do the bound shape properly, right? Well, thankfully, we don't have to struggle that hard. We could do something like far. And we could say name coming from the names collection. So we could say names. Then what we do here is we say if. And then, of course, name is equal to Nemo. And somebody says, oh dear, that's not correct. You better do names dot equals really Nemo. And that's another feeling stupid. Which way do we compare it, right? So notice what really is going on here. So we could be writing all this code. In the meantime, we got production code to release. And then we can say in this case, a found is equal to true. And somebody points out, but don't it, you forgot to put a break statement over there. Now, what this really means in this particular context is when I run the code, it says Nemo found. But essentially, what did we just do? So essentially, what we are doing here is imperative style. So imperative style is where you tell what to do and also tell, in this case, how to do it. So essentially, this is quite a bit of complexity that you have to deal with. So you tell what to do, but you also say how to do it. And the details are unapologistic to you. In a sense, basically what's happening here is it is on your face. It doesn't have any sympathy towards you. It draws you in, sucks you in, beats you down, and says, this is all the details you need to know. So one of the problems you have to deal with is to know what it is doing, you got to know all of it. And that's enormously complex for us to deal with. So how does it feel to write code in imperative style? Everyone has this in their family, right? I'm talking about that uncle that we try to avoid in family gatherings. You open the door, you step out, you see that uncle at a distance, you say, oh, no. Last time I said hello to him, four hours, my life was wasted. I'm not going to say anything. I'm going to take this other exit. That is imperative style code to me. Because when I look at it, it draws me in, sits me down, punishes me. So there is no relief to it. The entire complexity is on you when you deal with imperative style code. But we have all been writing this code for a long time. You probably will come across programmers who tell you, oh, come on. That's not too bad. That, come on, that's not too bad, has a technical term for it. It's called the Stockholm syndrome. Yeah, they did feed me every day while they kept me hostage. So the point is we tend to really be forgiving to these. And sometimes even would also tell you, but look at that code. It's actually simple. This is one of the problems we deal with as humans. So we often confuse innocence. We often confuse familiar with simple. And this is a flaw in our thinking. It's not your fault. It's not my fault. If you don't like the talk, you can tell me you don't like it. You don't have to turn things off. So essentially, the problem really here is that when you're dealing with something like this, oops, let's see what happens. There you go. Is it back on there? Awesome, thank you. So essentially, we often confuse familiar with simple. What is familiar is something we have seen over and over and over. And because we have seen it so many times, we just don't feel it. There's a difference between not having the pain and not feeling the pain. This is not feeling the pain. Why? Because we become numb over time with the pain. And that is kind of like a chronic pain we are dealing with. More morphine, we can get together, keep moving. But we can do better. So let's think a little bit about how we could rethink about it. So this is imperative style we talked about. But then the next thing I want to talk about is called declarative style. So declarative style is where we tell what to do. And you can say, but not how to do it. So essentially, you tell what to do, but not how to do it. So how do we do this? Notice I'm not adding code. I just deleted code. All that noise is gone. And I simply come down here and say names.contains. And I say Nemo right there and produces the same result as it did before. So what we did is declarative style. You tell what to do. Tell me it contains. And of course, the question is, how does the contains actually work? Anyone wants to take a guess? What does contains do compared to the code we wrote before? Same is a good answer. I like that answer. Any other answers? Maybe a super duper fast algorithm? Oh, they got to be using a hash code. Or the answer I like is, I don't care. OK, that's pretty rude. Let me rephrase it. It's encapsulated. What does that mean? It's encapsulated. I don't care, said in a polite way. That's basically what it is. So the point really is, it is under this layer. But of course, honestly, as programmers, we know one thing. We do care. Because, hey, what about performance? What about security? What about other implications? But here's the beauty. That's one click away. It tells you you don't need to know it right now. But if you do, press that button on your IDE. What is that, F12 command B? What are IDs you use? And immediately, you can look at the implementation. So it's not on your face, but it's just one layer below. As it turns out, there's a name for this, too. It's called SLAP, which is one of my most favorite principles, not physically to anybody. But in code, this is an amazing principle. It stands for single level of abstraction principle. So essentially, the idea behind the single level of abstraction principle is your code focuses on one level of abstraction, one level of detail. Anything that is a lower level detail, you push that and delegate it to another function. How does this help us? It helps to deal with complexity in the code. So you're not really spending your time enough for dealing with every single detail. So you can focus on your level of detail and anything that's a lower level detail. You delegate it to another function and say, go take care of it. Now, we talked about the imperative. We talked about the declarator. But you say, wait a minute. I thought I came here to hear about functional style. You're talking about declarator style. So let's talk about that a little bit before we go any further. But what is then a functional style of programming? So as it stands out, functional style is actually declarative style plus the use of higher order functions. So you're able to use higher order functions. So it's functional style plus the use of higher order functions. So this gives you the ability to focus on, essentially, not all declarative style is functional, but all functional style is declarative. This is one of the reasons why we tend to benefit from the idea of functional programming is because it's declarative by nature. So you focus on what, not as much on how. But we understand what declarative is. What in the world is this higher order function? Well, typically, we program with functions. So when you write code with function, what do we do? We pass objects, or we can say we pass data to functions. That's what we do. We take some data, we send the data to function, and say, go take this and work with it. We often create, if you will, data in functions. Not only that, we often return data from functions. So we tend to do these things with functions in general. So we pass data to functions, we create data in functions, we return data from functions as well. And as it turns out, it doesn't want to be connected anymore. Let's try that. So this is another lesson in architecture. This is the best way to demonstrate. The more moving parts you have, the more systems break. So this is just the philosophy we can learn from. There you go. Thank you. So excellent. Thank you so much. So that is one of the beautiful things. We can never have simple things because that's boring. And when we have complex, sorry? Simple scales. Yeah, simple scales. But who wants scalability? We want scale, not scale. So this is fantastic. But that's the nature of the systems we build and work with. Let's see, did that work? No? OK. Is that the correct one, though? Joseph? So this computer was a monolith. It turned into a microservice. And now we are trying to do observability, traceability. In the meantime, the customers are like, when can we have our product? But you don't understand. We're building microservices. So DevOps guy can tell us how to maintain this introduction as well. Yeah. The continuous deployment just crashed. Absolutely. That's a different screen. So it wanted to switch now. So is that still connected over there? No. OK. So let's try to change this. So I'm going to extend it. I'm going to mirror this. So let's see if the mirroring works. Yeah. How about that? Is that any better? Awesome. Thank you. Appreciate that. Thanks. So about two weeks ago, are we good? Yeah. Did that work? So about two weeks ago, I was speaking in CERN in Switzerland. And my computer would not connect. And I'm not kidding with you. They spent 40 minutes. And they couldn't get my computer to work. So I literally went over. Mario, who is a speaker, I said, can I borrow your computer, please? He was very interested. I said, here you go. I said, no, no, no. I want your computer with you. I can't type on your computer. So he was the typist I gave the talk. So the next day, I had another talk. And they called me up and said, you got to test this. Come early. So I went there, we tested it. And it connected. It worked. I said, this is awesome. Can you tell me how you fixed it? And they said, it's working. We have no clue why. Don't talk to us. So I started my talk saying, this is amazing, because here at CERN, they know how to take subatomic particles you cannot see and make them collide, but they cannot make a stupid computer connected in the projector. Go figure. So that's the word we live in. Anyways, amazing. So essentially, the idea here is when we have functions, we pass functions, we pass data to functions, we create data, we return data as well. But what in the world are these higher-order functions? What do they do? Well, the beauty of this is we can pass functions to functions, we can create functions and functions, and we can return functions from functions as well. And that's what makes a function a higher-order function. So not only can you do object decomposition, you can also do functional decomposition as well. And this is a powerful feature that we have. For example, if I ask you, if I have a pen, I say, what is this pen? It's an abstraction. You say, oh, that's a pen. But I can unscrew the pen. I will take the spring out of it, the metal, not the framework. And I can say, well, look, there's a spring. There's this ink in it. And I can disassemble into parts. You don't see the pen anymore. You see the parts. But I can put them back together as a pen. In a similar way, I can take functions and build bigger functions with it, just like I can take objects and build bigger objects with it. So not only can we have object aggregation, we can have functional aggregation. That is called functional composition. So that gives us a way for us to build the applications with it. But I do want to apologize to you because I'm a big fan of dad jokes. As I realized, one of the meaningful things of having children is to really tell really bad jokes to embarrass the children. So I'm a big fan of dad jokes. But I have to share a dad joke with you. And you need to answer this, so be ready. So here's the question for you. What is the most favorite animal for functional programmers? Anyone? Don't be shy. What do you think? What is the most favorite animal for functional programmers? Lambda. That's right. That's correct. You nailed it. Lambda. So what are lambdas? I apologize for that really bad joke. But usually people tell Python, I'm like, yeah, that kind of comes close. But lambda is the right answer. Thank you. So essentially, we're lambdas. Lambdas are anonymous functions. So functions typically have names lambdas don't. But lambdas have parameters you pass. They have a body, which is very concise. Proton type is often inferred. But you can specify that in some languages. So essentially, you're passing functions to functions. But those functions you pass really are the lambdas that you can pass. So we talked about the functional style. They had a lot of functions. But typically, though, we talk about immutability, functional composition I mentioned, and lazy evaluation. But I'm going to be lazy about lazy evaluation. We'll talk about that later. So we'll come back to that and talk about it. So that takes us to the main topic, which is to take the code and refactor it. But one of the challenges is the more you are used to one way of doing things, the harder it is to do it differently. So a lot of times what we know makes it harder for us to do it in a different style, different way. I come from about 35 years of programming and imperative style. I've been programming in functional style for 10, 15 years now. And so naturally, I can think imperatively a lot better than think functionally. And when I started programming this, it was really, really hard to think in functional style. And I remember one experience I would never forget. And I take a problem, and I was on a long flight, a 10-hour flight from Europe back to the US. And I was on the flight. I sit down. And the minute I sat down, I took a piece of code. Literally, it took me 10, 15 minutes to make it work, imperative style. So the code is working. Now I said, now that it's working imperative style, I want to make it work functional style. And I'm not kidding with you. It took me the next nine hours trying to find a way to write this code functionally. It was so bad. The flight attendant kept checking on me. You've got to look at the dude at 24, you know, L. He's kind of having trouble over there. And she would come over and say, are you OK? I'm fine. It's a stupid code. You want to pay programming? Be about this with me? So essentially, there was a stress rating. And at the end of the nine hours, a light bulb goes in my head. I get the functional code working. And I'm like, gosh, why was this so hard thinking in functional style? And the lesson I learned from that was the following. Don't bother with functional style. To begin with, you're not in a competition. You don't have to prove to anybody that you can write the code in functional style. So my code is I'm a big fan of this particular mantra. And that is make it work. And of course, once it works, if I know how to type work, make it work, make it better real soon. So I'm a big fan of making things work first. If things work, you can always improve it. And either you can improve it or somebody else comes and improves it. So make it work, make it better real soon. But one of the key things I would say, I know this isn't chart supply oftentimes, but if you write automated tests on your code, amazing things happen. Because when you write automated tests, you're able to know that the code is doing what it's supposed to do because you're verifying this with the test. Come and change the code to functional style. Run the test again. If the test works, you got it. If the test doesn't work, you realize you didn't understand the code in the first place. And this is something I really enjoy a lot because I'm a big fan of functional style. I would tell my developers, let's change this code into functional style. And we would modify the code only to see the test fail. Imagine we did not have the test. And the minute I say, here's a functional style code, isn't it awesome? And then five days from now, they find that it doesn't work properly. The next time I say I want to do functional style, they'll drag me out of the building. So having that feedback loop is very important to know it is working before and it's continuing to work after the change as well that can be very helpful. So given this, one of my recommendations really is write, first of all, the code in the imperative style until you get really comfortable with it, write it in imperative style. Then my recommendation is think, first of all, think declarative. This is one of the things that really has helped me. So don't try to take the leap into the functional style but think declarative, then code functional. So this seems to be a nice way to transition into it. So when I'm getting really tangled up, I'm like, I don't understand how to do this. I'm getting really confused. Just take a deep breath, step back a little bit and say, let me think about it declaratively. Let me think about what am I doing rather than how to actually do it. And detaching that helps oftentimes to figure out the solution, that's a journey we can take. But enough talking, let's take a look at what we can do to solve this particular problem. So what I wanna do here is to take a few examples and play with it. So here is a little example code as you can see and it says for the values one to seven, I wanna know if the number is a prime number or not. Now, this is a imperative style code we have written. And what do we do in this imperative style code? You are setting this variable called divisible. I know what you're thinking. You're thinking, come on, I don't ever call it divisible. What do you do? You say T, right? What is T? T stands for temp. But why don't you call it temp? Because that's how you tell the variable you don't deserve to live, right? Those are called garbage variables. Garbage variables are not part of the problem. They're part of the solution we create. And we give really bad names to garbage variables because they are uninvited variables, right? They're the third class citizen. We don't like them. So that's my divisible. And then we say as I iterate over this collection of a range of numbers, I check if it is divisible by that number in the index. If it is, I set divisible to true, I break out of the loop, then I come back and check it. Now, the question is, if you have proper tests, you would verify that it's working. In this case, it says one is not prime. Yeah, it's not. Two and three are prime. Four is not five is. Six is not seven is. But I wanna write this code in functional style. How do we do it? I think declarative and then write functional. So what are we doing? I can say a number is prime if for the range two to number minus one, no number in the range divides the given number. So we could say no value in the range to avoid confusion divides the given number. So now we have described the behavior of what a prime is. Once we write this down, we can look for some key things in here. Given the number, yeah, we have a number. It's prime if for the range two to number minus one. So we need a range operation, great. What else do we need? And then we say no value in the range divides the given number. Well, the value in a range is being divisible as a predicate, but nothing in it. So no value in the range, you can think about a few different options. It's a none match. So essentially it becomes no match or none match and you can start exploring things and you can find what that really means. So now that we have a little bit of a handle on this, we can go back here and say, I want to bring in import. Let's go ahead and import here. Java dot util dot. In this case, a stream dot start. And I want to come down here and say, here is the divisible number is greater than one. And in the stream, we can say, dot range two to the given number, we can say. So then what do we want to do? Two to the given number. So here is the value in that range. Then I can say dot none match. Given the index, I want to say, number mod i is equal to zero. So essentially we can convert that to a functional style by simply using the range function and then we use a none match to it and then we can execute the code and we can get the response as well. So essentially we want to think about what we are doing and then start looking for the functions after that. So what have we learned from this little experience that we had right now? So we can start gathering some collective knowledge at this point. So if you have a imperative style code, imperative style code, and you want to be able to convert it to a functional style, so you have a traditional far i equal to zero and then you have a range of values. So that literally becomes the range function. So you can use a range where you see a far that becomes a tool to look for in terms of what to refactor that is something we can do. So we started with this code. It's a lot less noisy, no garbage variables. There's no that divisible variable is gone. We are using the higher order function, which is what? Well, none match is a higher order function. Why is that? Because we are passing the lambda expression to the none match, passing the function to a function. None match is the higher order function that we are using right there. And of course, that's a refactoring we did. So essentially, start with an imperative style code, but think declaratively before you jump into functional, that gives you a handle to know where you need to approach and you can start experimenting with it and then you can move forward. Well, great so far, but let's go a little bit further with this to see the next thing we can do in here. So here is a little function which is going to compute the factorial. And what does this function do? It says the result is one and then for every value in that range, I'm gonna do a multiply and take the value and keep multiplying to the previous value. So when I run the code, you can see the values for the factorial. One, one, two, one, 20 and so on. So the question is, how do I refactor this code to functional style? So there are a few things you can think about, look for in the code that are giving you the clues to look at what you wanna do. This is a skill we need to take time to develop. In a way, I would say metaphorically speaking, imagine you're wearing a functional style dress and you put this glass on, you don't see the imperative code anymore, but it shows you the pieces that are functional and imagine this is like a, this will be a nice business to have by the way and AR glasses for functional programming. You put these glasses on, it shows you the functional code for imperative style code. And I have such a glass by the way, that's glass I put it on and you can ask me, what do you see here? I see the reduce function right there and that's a technique we need to take to develop. Why do I see a reduce function? The clue here is notice the result on the right side and the result on the left side. We all know what that means. It's called the successive refinement of a variable. So if you keep refining a variable, that's a reduce operation. So what does a reduce do? Reduce operation takes a collection of data but reduces it to a single value. Oh, by the way, this is an amazing feature in programming languages. It's as if the authors of the language get together for dinner and they ask each other, what do you call that function? Oh, you call it reduce. I'll make sure I call it something else. So they work so hard to come up with different names. Hey, what do you call this in C sharp? They call it aggregate. What do you call this in Java? We call it reduce. What do we call this in Groovy? We call it collect. What do you call it in Ruby? We call it inject. And the next programming language is like, what word is not used so far? I can come up with that. Oh, fold, thank you. And Scala calls it fold. And in fact, fold is not enough. You can fold it left or fold it right. So you have a fold left and fold right as well. But that brings us to the point. Imagine you have a little mat. You're doing your gym plank. You work out. What do you do after you work out being a nice person? You roll it, right? Absolutely. And you can roll it to the left or roll it to the right. Don't get too anxious. It doesn't matter which way you roll. In the case of mat, at least. And then you stack it up against the wall. That's why it's called a fold operation. And that's what C sharp calls, sorry, F sharp. Oh, that's even better. Everybody has flaws. But Microsoft has the biggest flaws. Because it's the same damn company. The C sharp team called it select and where. And the F sharp people are like, we can't do that. So they call it different. It drives me crazy. Because when I do F sharp, I have to use different names for the same thing when you see sharp, right? Go figure. But anyways, at the end of the day, we need to recognize all of these are reduced operations. So reduced comes in different flavors. Collect, inject, fold and aggregate and so on. That's a success of refinement. Oh, but by the way, what is this in here? My glasses show me that's a map operation. Because you're transforming the data for every eye, you're transforming it to a value. So you recognize a map and you recognize a reduce in this code. So now we can take this code and we can say, aha, I can do dot, you still dot stream one more time. And now we can go back to this code and we can say return into stream dot range. Oh, but wait a minute. Notice it's less than or equal to, so that becomes a range closed. So back here, if this was a less than it is range, but if it's a less than or equal to, that turns into a range closed. Because the range closed includes the ending value, whereas the range excludes that. So this becomes a range closed from one to up to, so we are iterating through all those values. Then we say dot map, but we are not mapping an integer to an integer. So we say map to object. We wanna go from an int stream to a stream and we are saying, given our eye, I wanna convert it to big integer dot value of eye and we do a map operation on it. And once we transform that to a map operation, we do a reduce operation. So what does a reduce operation do? The reduce operation says, I'm gonna successfully define this value, start on one end left and keep going to the right and refine it. So this is gonna say, I wanna start with a big integer one because that's our initial value we started with. So that's our first value. Then we say a product because that's what we are trying to do. Oh, by the way, this is another thing that drives me crazy. How many times have you seen developers do this? They call it X. That's a beautiful name, isn't it? Or you call it P. I mean, seriously, would you do this? Would you name your kid P? Child, what's your name? My name is P. Really, is that your initial? No, that's my full name. The only reason that ever happens is both the parents are programmers. If one parent is a programmer, the other one is not, child is safe. Hey, I wanna name the kid P. Are you out of your mind? And there's a force of people on you, right? But if both the programs are programmers, it's like, I wanna name the kid P. Oh, I love you, this is great. And the poor kid, that's what happened to Elon Musk, right? What a disaster in naming. I don't know how the child is gonna deal with this poor thing. Give it good name, respect your variables. This is product. You know, what is the risk of calling a product? People understand. They're not trying to wonder, what does this variable mean? You know, I always wondered, I used to think, why do people do this, right? You got a series of code. This is called maybe, you know, X. This is called W. This is called K. And one day I was thinking, what does all this variable mean? And I was like, maybe, maybe my colleague was abducted. And the person who abducted them said, you keep writing code. So nobody knows you're being abducted. Maybe they're leaving a secret message for me at the location where they're hiding. No, that didn't really mean anything, right? And maybe eventually I figured out, maybe they're programming with their cat. I mean, it's a great thing, right? You're coding, you attend a phone call, your cat jumps on the keyboard. I mean, if my cat gives a name, I'm not gonna change it. I'm like, this is great. I tell them, at least comment, who can we attribute this variable name to? Name your cat in there, right? But I think we can make the code a little readable. We can respect that and say, oh, this is a product after all. So product and what is the next one? An index, right? Usually an index variable is I, but this is a value that you have. So we can say value. And what do you wanna return from here? Big integer dot multi, pardon me, it's a product dot multiply and the value that you have. So now we wrote this in functional style and we can run the code right now and make sure it's doing the job. Ooh, let's fix this. So this is going to be the value that's a product coming in and we are, oops, a little error there. There we go, let's fix that and run the code and incompatible lossy type. Ooh, let's see what the type, oh, of course. This is big integer one and line number six is not happy with me. Let's take a look at line number six. So in here, we have, oh, this is a long, isn't it? So long stream, not into stream. You're, oh, sorry, not stream. So long stream, there we go. So long. So now we can run the code and you can see the same result as before and that gave us the result. We can stop here if you want to. But if you look at this lambda expression, what does this lambda expression actually do? Now you can have lambda expressions that actually do some work. For example, I may have a lambda, for instance, just as an example, I do a map and you can say given a value, you could say value times two. That's doing a little bit of work, isn't it? You could say plus 10, that's doing some work. But what does this lambda do? It takes an input and passes it in to this function. In other words, it does absolutely nothing other than just passing the value. This reminds me, I know this is an old movie, but you probably have seen this. Remember seeing the office space movie? In that movie, they ask Tom, what do you do? I take the requirements from the business people and I give it to the programmers. And the guys are like, why can't the business people give the requirements to the programmers directly? Damn it, I'm a people person. I take the requirements from the business people, I give it to the programmers. So I call this one the office space pattern. It is not doing anything useful. Well, not only is it not doing anything useful, we give a really terrible name for this variable. You're forcing people to read a code they don't have to read. So what you can do is, these are called pass through lambdas. Pass through lambdas simply pass their parameters through and do nothing. So you can replace them with method references very easily. So as a result, you can get rid of the lambda and simply write a method reference. And you recognize not only was that a pass through lambda, this one is also a pass through lambda. It takes the two parameters and passes them as arguments. So we can get rid of that as well. So we can say big integer and we can write a method reference right there and we can simply remove that as well and we can write that as a method reference. Well, with the method reference, you spend less time reading the code so it becomes easier to understand it and it taxes you a lot less as well. So where possible, definitely use method references. But what did we learn in this case? First of all, if you are transforming data that you are value of, what function do we use for that? We use a map function. And your successive refinement of the data, what do we use for that? That's your reduce operation. So we can start putting together these kinds of functions to work with. And we can start recognizing things we do in imperative style and the equivalent of it in functional style. We can start gathering some of these ways to refactor. But of course, one of the things is to avoid the mutation as well. If you saw the code we saw earlier, it was mutating the variable. Now we are not at least explicitly mutating. We'll come to the mutation later on and the code is a lot more expressive. So here is one of the nice things about functional style code. Functional style code reads like the problem, like the problem statement. So essentially that's one of the biggest benefits you get. When you start reading the code, it begins to flow like the problem statement. What does this code do? Given a range of values, find their values as big integer and compute the product. So you are just drawing through the step after step. It becomes easy to understand. When it comes to an imperative style code, what do people, people are very polite. These are called euphemism. You go to somebody and give them an imperative style code and say, what does it do? What do they say? I'm trying to figure it out. What is the word in English? I'm trying to figure it out mean. It means the code sucks. We don't know what it is doing. We're struggling with it. What do we say nicely? I'm trying to figure it out. I don't want to figure out what your code is doing. Let it be obvious to me when I look at it. So imperative style code hides the complexity and tortures you with it. Functional style code flows and makes it obvious what you're doing so you're not taxed. It reduces your cognitive load. So that brings us to one other function I want to talk about here. Let's go to the next example. And notice what I'm doing here. I have a search word is equal to local host. Then I have a file, et cetera, host. I want to find how many lines in the file have the word local host. So what do you do? I apologize for this already, but we create a buffered reader and point it to the file. Then comes the scary code, string line equal to null. Then we say, go read the line, assign it to null but check it for not null. How do you feel when you look at this code? This is the kind of code you will hide from humanity. You will never, ever want to show a code like this to your children. If you ever show this code to the children, they will never take after the profession. I really wish they had told me this when I was younger. You know, I travel a lot. So when I go home, I want to spend time with my kids but I also have work to do. So I would take my children, put them on my lap and then I would be coding. And when they're really small, what do they know, right? So they're sitting there and watching things. I keep coding. They slam on the keyboard for a little bit and then time goes on, they're still on my lap but they begin to learn. And one day my son as was coding away, he said, I said, oh my gosh, are you okay? He looked at the screen, he looked at me. He looked at the screen, he looked at me. I said, is everything okay? And he said, dad? I said, yeah. He said, don't worry. When I grow up, I'll take care of you. You don't have to do this anymore. And I am the last Subramanian who will ever be a programmer in my family. Because my children said, dad, this stops with you. No more of this programming stuff. This is what happens if you show bad code to children. And I wish they hadn't told me how to shut the door and I'm secretly programming. Nobody should see my code, right? But this is a code that kills really hard. So that's verbose, isn't it? Then we say lines.contains, at least that's a relief. Then we say count plus plus. That's mutation right there, which we created up here. So the question is what can we do to solve this problem? First of all, notice this F. This F is saying do something or don't based on a condition. So and if in your imperative style code readily turns into a filter, hey, that's great. And I'm gonna look at the count to plus plus. I want you to tell me what that seems like. Count plus plus. You take the value of count, add one to it, put it back to it. What does that feel like? Come on. Current value of count becomes a new value of count. It's a successive refinement of count. So it's a reduce operation, bingo. That's reduce right there because you're successively refining it, isn't it? Old value of count, new value of count. Old value of count, new value of count, successively refining it. So that's a reduce. But a reduce comes in many different forms. Some is a reduce. So when you see some, recognize it as a reduce operation. So almost we have everything almost. What is the one thing we don't have? In the examples we saw so far, if I start with a stream, I can do filter map and reduce. But if I start with the stream, but what am I working with here? Not a stream, but a data from a file. So the only question left in our mind is the following. The question is, can I convert strings in a file into a stream of strings? So you are like, I've got half my puzzle solved. If you give me a stream, I can attach a filter map and reduce to it. The only part that's missing is I need a stream. Can I convert a file to a stream? That's a question. As it turns out, the answer is yes. So we can go back here and say java.nio.file.star. And I can simply say over here, I can say a return files.lines and I can say packs.get. And the file I wanna get is the path that's given to me. Dot, hey, what are we doing? A filter, because for every line, I wanna say a line dot contains the search word. And now that I have all the lines with the search word, I wanna do the count. So we can get rid of all that now. And this becomes a count. So I can simply say avar count is equal to and the count I can display right now. So, oh, illegal start of expression. Let's make sure I've got this proper. So that is my count. And I'm gonna say, oh, no return, right? Where did the return come from? So essentially in this case, I want to take the value and put it back in there. And the result is three as it was before. So essentially, what is, so, this is one other thing we need to get better at. If I point to that line and I ask you, what is that line? You must be able to say that's reduce operation. Count is a specialized reduce. Some is a specialized reduce and so on. So you can use these specialized reduce operations in addition to a general reduce operation as well. So that is basically a reduce at the very end. So you do filter, reduce, filter, map, reduce, map, reduce. So you're basically using these kinds of operations. That's basically what you did right here. Again, no explicit mutability. And we used a filter and a stream and we're writing on it. Okay, so far so good. But the things can get a little bit more complicated when it comes to imperative style code. And one such example we're going to see here is the next one I wanna show you. Let's see if that's gonna bring it up. Oh, let me try to pull this up again. So yeah, so what does this do? Notice in this case, I have scores. So I have scores, Jack has 12 points, Jill has 15, Tom has 11, Darla has 15, Nick has 15, Nancy has 11. But what I wanna do is to group them based on the score. So I wanna say for 15, I have Jill, Darla and Nick. For 11 I have Tom and Nancy. For 12 I have only Jack. So how do I group them based on those scores? Now we all have written imperative style code. Let's take a look at what this imperative style code is doing. We are starting with the given input. We create an empty hash map. Then we say for every name in this collection, for every, you know, in the scores, we'll get the score for it, 15, 12, 11. Then we create an array list. This array list is called the victim array list. Why? Because it may get thrown away. We may not even use it. Poor, sad array list, isn't it? We create this one. We check if the key exists. If it does, we pull the array list from the collection, discarding this one. We update whichever collection we have and then we put them back into the store. Raise your hand if you like to write this code. Not really, right? So what do you do if you have to write this code like this? That's why we hire interns, isn't it? So you tell the intern, go write this code. And they're so happy you give them the job to do. And they're writing this code while you take the lunch, long lunch. Well, poor interns, we don't wanna torture them, right? That borders the line of cruel and unusual punishment. This is too low level. This is not the kind of code we wanna write. But let's step back and think about what we are trying to do. So we have all these names, right? We have Jack with 12, Jill with 15, Tom with 11, Darla with 15, and so on. So I want you to think about this conceptually a little bit differently. I'm a big fan of imagining things. Because if you imagine things, it becomes easier to code. One of the places where we get really tangled up is we take our things too seriously. Oh, I'm writing code. Well, you get tangled up. You're not able to figure out how to write the code. Walk away, step away. Think about stuff. It becomes easy to write the code after that. Hey, so I want to group them based on these numbers. So what would I do? If I have a bunch of kids at home, how would I work with them to do this? I'll go tell them, look at me five or six buckets. Oh, now they have some buckets. Let's put some labels on the buckets. A label on one bucket is called 11. Label on another bucket is called 15. A label on another bucket is called 12. Now I tell the kids, when you see a bucket with 12, drop Jack into it. When you see a bucket with 15, drop Jill into it. Now notice conceptually what you're doing. You got buckets and you throw things into the bucket. So all you have to do is tell which bucket to put that into. Becomes easy. If you understand that concept, you just understood what grouping by does. That's exactly what grouping by does. 11 has Tom and Nancy, 12 has Jack, 15 has the other three. Notice what we are going to do. We take this bulky code. Look at this horrible code. What are we going to do instead? We first of all go bring collectors into this. Once we bring in the collectors, collectors as a function to group, but let's see what we're going to do. So we say return and we take the scores dot key set, dot stream. So we're working with the stream of the names given to us. Dot collect, grouping by given a data, tell me the label of the bucket. That's all you're doing here. That's a very powerful concept is in there. You're saying I've got a group of data coming in as you work with this data, simply take the data and put that into a bucket with that particular label and rest his history. Now you got a buckets that you can group together and you're done. Well, if that is so, what can we do here? We can say given a name, I want this scores dot get on the name. And that becomes, and this is shocking as in it, you took all that bulky code and replaced it with just the three lines of code. And you run this code, it's got exactly the same result. And you just told what buckets to put into. So what does the grouping by do? You tell it the bucket to drop into and you might observe this and say, wait a second, isn't that really redundant? Sure, you can simply replace that with a method reference as well. And so right now you can run the code, produce the same result as well. So that becomes a grouping by operation. And you can see how concise this code is compared to the monster we wrote a few minutes ago. This is easy to understand, easy to read if you understand this idea of putting things in the bucket. So you still need to understand what these functions do for you. But think about this like we can keep doing manual labor, we can keep digging and plowing or we can press a few buttons and have the machine do the job for us. But of course to operate the machine, you need some more education because giving the machine to a person whose layman is dangerous, somebody's arms and legs may be lost doing it. So you need a little bit more training on how to use these functions, but then you become more productive using them. That's the benefit you get out of this. But that's where the training comes in to think about, go think about this as a bucket into which you drop, then it becomes easier to think about it. Well, so far so good we saw how it went away from this verbose code to something really simple, but I wanna post a little challenge to you. So we're gonna look at two more examples before we wrap this up, but this one is gonna be a challenge. And I'm gonna show you a code and this code was sent to me by somebody and they said, here's an imperative style code. How do you, oh, both this and the next example are examples people sent me. And here's an imperative style code. How do you write it in functional style? That's the question we're gonna answer. So here's the code I wanna start with. So what does this code do? First of all, if you notice, a little bit tricky. Hi, what word is being repeated? The answer, what letter is being repeated? The answer is nothing. So it's empty. H is not repeated, I is not repeated. And I'm gonna ask the question, what's repeated in each one of these? What is repeated in here? L is repeated, right? So L is the letter that's repeated. What's the first letter that is repeated? The first letter. So P is not there, U is not there, R, aha, R is there. So R is repeated, right? So here's the R and the R is repeated. So it appears twice. What about Jaguar, what's being repeated? A is in there. A appears another time. What about here, what is repeated? H, because H is the first letter that is repeated. Not the L, L is the second letter that is repeated. But H is the first one in the sequence, right? So the goal is to find among us string which is the first letter that is repeated. So here is a code that somebody sent me. They said, first I will split this into a char array. So here I have the letters. I'm gonna loop through for every candidate letter in the letters, count is zero. I'm gonna check if char letter, again an iteration. If the candidate is the letter, count plus plus. If the count is greater than one, return that value and you're done. So that is a imperative style code to find the first letter that is being repeated. So what did they do? They take a letter, they go through the entire word looking for it. If it's not present, go to the next one. If it's present, count is greater than one, you're done, get out. I wanna write this code in functional style. What are your thoughts? How could we implement this in functional style? That's a question. Don't worry about being right or wrong. The key is to be able to think and see what can we do. And it's a struggle, sometimes we get it, sometimes we don't. Filter, we can filter, I like that idea but what can I filter on and what would I be looking for? I can take the character and I can filter it but it's gonna give me the same letter that's there because it's already there when I filter it. But I don't know the count when I filter. We need a little bit more, right? So I can say, given a letter, check if it's there in the letter in the word, it's there. But it only is there once, how do we know it's there twice? I can split, I can start filtering after the split but then how do we do that? Need a little bit more. You can use a map and group by. Let's start with that. Great first thought. But how does that feel? Does it feel like it was a little bit more heavy handed solution? Maybe you have to create an entire map and then come back and look for it. Will it work? Yes. Yep, got it. Bingo, yep. So H is one, H is two and then you group by. Yes, but does it feel like it's a lot of work? Great first thought. And if you ask me, did I ever think of it? Yes, that's a good first thought. So sometimes the hardest of solutions are the simplest because simple solutions hide behind the complexity. Complex code is like me, loud. Simple code is like, have you seen this one before? Right? And some of the smartest people are the quiet people, isn't it? We know that. I'm the loud. They're like, have you looked at this solution over here? Simple code is the quietest, hard to see, hard to sense. So sometimes we look for solutions but we gloss over simple as code because we're like, that cannot be used. So to answer this question, let's step back a little bit. I like to experiment with code. And there are many ways to experiment. You can use an IDE, fancy IDE, you can write code in IDEs. The problem with IDE for me is it's too slow. You write the code in IDE, you gotta go click a button, you can run it and you can say, oh, Venkat, you can use a shortcut key to run it, sure. But that is if I first started the IDE. And what does an IDE say? Welcome on board, you gotta create a project. I'm like, I wanna just get my work done. But we will tell you how to structure your code. I'm like, dude, I just wanna play with some code. So there are two ways to do it today. Java now has what's called a playground. Anyone who has used the playground so far? Thank you. I don't, but there's one person who has used it. Can you say a few words about playground? Do you like it? It's beautiful isn't it? So playground simply is a browser page. You go select the Java version, you write the code on the browser, how cool that is, and you run it in the browser. You don't need to install Java on your machine at all. So you're visiting family, a little niece or nephew says, is Java nice? You say, of course, sweetie, Java is awesome. And they're like, really? How would it look? Let me show you. And just take your phone, go to the playground and show them some Java code and you spoil them for life, right? How cool that is, right? So you don't have to install anything. You can just play with it right there. So you can use playground. I'm a big fan of JShell. I love to use JShell because it just comes up right there. I can write some code in it. And people often say, well, you need an ID to do anything serious. Well, really. So we can say, you know, greet equal to hello. And how cool this is. You don't even have to put a semicolon. Isn't that cool? You just wrote that. And then you say greet dot index off, I can say. Then people say, well, if you're using the real IDE, it'll expand the code for you like it just did. So it can expand it for you too. And they say, but if you use the real IDE, it'll give you documentation like that. And you can even look for the documentation. So you have the whole shebang in front of you in JShell. So it's pretty much your IDE within a command shell. I actually have seen developers using IDE and use JShell within the terminal. You can even have a cake and as I did it, right? So why not? So I can say, I want to know where L is in this particular case. Oh, L is two in the hello, right? So greet, as you know, is hello and L is in location two. But I can say greet dot last index of L, aha. What is that? That's three. But if I say greet dot index off, and what am I looking for in this case, index of H, that's going to be a zero. But a greet dot last index of H, what does that end up being? Well, that ended up being zero as well. So now exactly we have some ideas to play with this index. So I can say here, aha. So return, and I can say word. So stream dot off word dot split on the empty. So I can split on it. And once I split it, obviously in this case, I need the import Java dot util dot stream dot stream. We'll bring that in. So once I split on it, what's my next step? My next step after splitting on it is to say filter given a letter, I'm going to say word dot last index off the letter is greater than word dot index off the letter. Does that make sense? When will it be greater? Only if it's repeated, not otherwise. Okay, so far so good, but what am I looking for? I want the very first one dot find first. And here's the charm. Find first is lazily evaluated. Find first will not keep going. The minute it finds the first letter, it's like I'm done, I'm going home. No need to do anymore. Well, what does find first return an optional? You say RLs give me the empty. So when you run this code, you can see the same output as before. But just to confirm what I said, this is lazy evaluation. So let's take an example and play with it. So if I go back to this variable, this one here, so let's just take this one. And so persevere, what does that do? It's going to take P, it doesn't exist. U doesn't exist or does. So you should never touch S-E-B-E. That's when you know it's got good performances in there. So when you run the code, it tells you the responses are, but how do I know? This is an interesting little tool you can use called peak. And you can take a letter and you can simply output the letter. So it gives you an opportunity to just peek into it. So when you run the code, notice it says P, U, and R, but it never went beyond that because R is the first match and it's like I'm out of here. Please. It just simplifies the code, that's it. It doesn't reduce the runtime complexity. It reduces your, same as before. You're not doing any worse. But memory-wise, you're not taxing it. Had we created a map, we would have caused the space-time complexity, right? Right, but you'd use more memory in this case if it's a large collection, trade-off. And I would say experiment with it, that's the best way. I never take S-O-N-O for an answer. I always say show me the code, compare it, contrast it, and then decide which one is better. One is better than the other, take which one is better. That's the key. So essentially in this case, you are using this ability to do lazy evaluation. And when you do lazy evaluation, you're not really computing things you don't need to compute, life becomes a lot easier. So that brings us to the last example I wanna show you here. This is an example that somebody sent me and said, look, I know exactly how to do filter map and reduce, but how can I solve this particular problem? So they said, I have compute triples. So given a value 10, I wanna be able to compute triples, sorry, given a 10 values, give me 10 values, compute 10 triples and print it. But what is a triple? A triple is a Pythagorean value. So you have A, B, and C, for which A squared plus B squared equal to C squared. And that's what you wanna compute. So if you run this code, we want 10 values. So notice the very first one, three, four, and five. So three squared plus four squared is 25, which is five squared. Similarly, 940 and 41 is the 10th value. You can, it's an infinite series. You can create as many values as you want to. But in this case, we want only 10 values. So the question is, how can we write this code in functional style? But let's understand the imperative style code first. So we start with a count equal to one. And by the way, this is called the Euclid's algorithm. And Euclid's algorithm says, you start with the value of m from two to infinity. You start with the value of n that goes from one to the value of m, upper bound. You get the triple using that function you saw about, which does this. And then you increase the count. Once you increase the count, if the count is greater than the number break from the inner loop, if the count is greater than the number break from the outer loop, that feels morally wrong, isn't it? That you have to break twice on the same value. But that's because you got to get out of the inner loop and the outer loop. So the question, how can we implement this in functional style? That's our last refactoring we're going to do. What do you think? What are we going to look for is the question, right? Anything comes to mind? All right, I'll give you a clue. I want you to look at this. That's your loop. Value of m goes from two, three, four, five, six. Here's an inner loop, value going from one, two, three all the way to m. And then you are getting a triple. Only look at this for a minute. What comes to your mind? Given a value, you're getting a triple for it. Given a value, you get something else. Map. So we know that's a map, bingo, right? So there's a map in there, but the map is a little bit more complex. And I want to get to that with a little example to understand what this means. So a little detour if you don't mind. So in this case, oh, I forgot to update this, right? So we saw the files, sorry, you have a reading from a file, right? Reading file that became files, dot lines, which gave you a stream. We saw that as well, right, very nicely. So that was a useful operation. And similarly, what did we see in the next example we saw? We saw grouping by. So when you're trying to really collect into groups, you can use the grouping by. And in the grouping by, think of it as the buckets to conceptualize it, that becomes a lot easier. And similarly, find a first really becomes so break, right? So break on first value can become a find first. But let's come to this one. I wanted to think about a stream dot t dot map. And you take a function, I'll call it as one-to-one function. What is a one-to-one function? One-to-one function is given one input, you get one output. When you have a one-to-one function, this returns back a stream of R as a response, whatever the return type is. So that's good so far, right? But if you have a stream of t, and you say map of a function one-to-n, given one value, it gives you a collection of values. So given a person, I want their date of birth. Good news, everybody has one date of birth, right? But if I ask you, I want all your email addresses. Some person may have one email address, some may have 10, but I want all of them. That's a one-to-n, one-to-many, right? One-to-many. So what does this return to you as a response? It's gonna return a stream of list of R, maybe. But the question is, is it what you wanted? So the answer is, if you have a one-to-one, one-to-one function, use map. If you have a one-to-many function, and you guess, use what? Flat map, works really well. So if you have a one-to-many transformation, use a flat map. So the key here is to look at the code and recognize that you have a one-to-many mapping. How do you have a one-to-many mapping in this case? Given one value of m, you have many values of get triple because there are many values of n. That's a one-to-many mapping. The minute you see there's a one-to-many mapping, you know it's a flat map, boom, you got the answer. So when I run the code, you can see it says 345, 940, 41. Let's go back here and work through the flat map problem. So look at that nested if and double, if, we don't have to mess with all of that, return. And I'm gonna say in this case, a stream dot eta rate. So eta rate and what? I'm gonna start with the, was it a two? So I'm gonna say start with a, okay, let's do this again. So in this case, I'm gonna start with this and say in this particular case, let's go back and say, yep, two. So let's work through this here. So I can simply say, let me bring in dot stream, first of all, start with that. So back in here, let's say return a stream dot eta rate two to m given m m plus one dot. So we took care of this for loop right there. What about this one? We say dot flat map as we talked about, given a m into stream dot range, is it range or range closed? Range from one to m dot map, map to object, we have an n given to us. We call get triple m comma n. So we got back the flat map for this particular map. Then what are we gonna do as a next step? We wanna count plus plus. What do you think is the count plus plus going to be? Because we wanna keep incrementing the number of values, right? Well, in this case, our goal is not to actually do the counting. We simply say limit the number of values. That's how many you want. And when you got all the values, what do we do to list? Put the back in a list and send it to me. So that becomes the code to execute it. So we used a flat map for us to perform that operation. So one to one mapping use map. One to many mapping use flat map. And so the minute you recognize the one to many in it, it becomes a flat map problem very quickly. And that becomes a nice way to transform it. So the bottom line is this. This journey can be a bit messy. I'm gonna stop with this one. This journey can be really messy. And but there are some things we can do to get better. There is nothing like practicing. Practice, practice, practice. So a lot of times I would say, there's a great way to invite a colleague at work and say, hey, here we have our imperative style of code. Let's sit together. Let's start refactoring it to functional style. That's a great way for us to get better as a team. So invite a colleague and say, let's just refactor this. And we both may struggle, but we get to learn from each other. That's a great way to raise the bar of the team is to pair with developers to refactor it. Work on some exercises. When you have a problem, you see that, and I do this quite often. I'd be working with something. I say, ooh, that's a imperative style code. I wanna convert that to a functional style code. This can be really a great opportunity on long flights. Keeps you away from watching them in, I mean, this beats AV in-flight entertainment you can have, right? If you want a horror story, you got that right in the code, right? It's got comedy, it's got drama, it's got tragedy, it's got everything built into it. As long as it works in the end, right? You walk out smiling and say, ooh, that was a journey, right? And this can be really rewarding because the more you try, the more you practice, the more you tend to really figure out things and you'll bring rewires these thought process. I'd be delighted to answer any questions, but that's all I have. Questions, comments, thoughts, anything. I'd be delighted, please. Beautiful. So the question is, for the functional style, which is the language that's the most suitable? The one that you are programming in? And I'll tell you why I say this. We can be theoretical about things but I'm a very practical person. I want to get my work done. That's the first thing. And along the way, I want to improve what I do. If I had the opportunity to go learn a different language and use that language in production, that's great. I also teach part-time in the university and I had a gentleman who has about 15 years of experience and I was doing a programming language discourse, so throw them into multiple languages. So they programmed in Scala and they programmed in Clojure. And my student came to me and said, I think Clojure is better than Scala. I said, I'm not gonna argue with you but tell me why. He said, I was programming in Scala and I had really hard time thinking functional. I started writing code in Imperative and it just let me do it. I was programming in, actually it was Erlang, I think it was programming not Scala or Clojure, but nevertheless, I was programming in this language and it said, my way or the highway. And it will not let me write the code in any other way than functional. I had to fight with it and eventually it made me write the code in functional. That's great from a learning point of view but that's a disaster when I have code I have to release in production because my boss is now going to be kind to me and say, I understand, take your time. If it takes 15 years for you to figure out that's still okay, right? So I got to get my work done, make it work, make it better real soon. But having said that, I do find languages like Haskell to be very rewarding because when I learn these languages it gives me the ability to think differently then I can come back and apply that in any language. But the point really is you wanna make that paradigm shift. That's the most important. You can do that in any language. Some languages may force you. Some languages may not force you and you may have to really force yourselves to think about a few things. But the problem is this. If you are gonna be dissuaded from practicing functional style because you now have to learn the syntax of a new language before you can learn functional style. And if that is keeping you away I would say the language you're programming is the best one because to me the goal is to learn things and apply rather than giving excuses to say I really wanted to learn this but my gosh that's an uphill battle, I couldn't take that anymore. And that's what I would say be practical about it and that way you can gain something out of it. Good question though, thank you for asking that. Please, beautiful. I love that question because I think a lot of people pitch bad things against each other. Let me emphasize this. So what I wanna emphasize here is I wanna really say this simply. Oh, it's not your enemy, it is not. How many of us have benefited from object-oriented programming? All of us. So let's not bash what has helped us, right? The problem is not with object-oriented programming. The problem is the way we use it. So what is the influence on this? I today use OO programming with a lot less state than I used to. When I work with developers, public class, private field, whoa, wait a minute, what was that? It's a field. Why'd you write it? They say, what do you mean? I need a field. No, you don't. Don't bring a field until you cannot implement this without a field. So my code has less state now than it used to. So your enemy is not object-oriented programming. So what is your enemy? Your enemy is the complexity that is in the imperative style. So fight that. So I use object with functional. So here's a way to think about it, right? Just a stupid analogy. I'm a big person of analogies. So I'm saying, I wanna build a house. I wanna build a wall. How do I build a wall? Well, dude, you need a brick. Great. But how do I, I don't stack up a brick and walk away, right? That's dangerous. It may even fall on me. So what do you do? You can take a brick and you can put them together using clay. Not saying that's a great idea, but you could do that. Or you can take brick and you can put a cement on it to connect them. So now you know where I'm going. Your brick is the object. You can connect it using imperative, which is your clay, or you can connect them using your cement, which is your functional. So think of these as glue. How do you work with your objects? Well, I can work with my objects using imperative. I can work with my objects using cement, functional. And I can go back and forth, but you got that ability to mix and mix right now. So to me, the object is not the problem. So when people tell me, oh, oh, oh, please pad, function is better, like you missed the point. Opti-term programming allows you to deal with complexity. So your enemy is not objects. So your enemy is the complexity and imperative style. So beat that complexity. That's what I would say. Beautiful, love it. We have this room until five AM, right? Because the question is what happens to design patterns? Let me put something out before I go into it. The more design patterns we see is a sign of lack of capability of a language where we use them. Let me put it in a slightly different way. The more capable, you could say capable language is the fewer patterns we will use. So a lot of times design patterns are a way to compensate for something that's missing. You're saying, I wish I had this, I don't, I'm using a pattern. If a language is really powerful, we call them features, not patterns. So when I first got into Java, it was like a light bulb moment. Because things I would call as patterns in C++ were just features in Java. With Lambda, I almost relived that experience. The patterns in Java were just features now in Java. So patterns get hidden into language features. So a great example of this is passing Lambda's to functions is really a very simple concept in Java. We call that higher order functions. But what does it mean to pass a Lambda to a function? Using Lambda to function is really the strategy pattern. You just don't call it a strategy pattern. Why? Because it's normal life now. What did you do for strategy? Oh, design an interface, implement a bunch of classes, and you forget why you started doing this in the first place along the way. That's so much code you had to write. Whereas here, just create a Lambda, pass that in, and you're done. So it becomes a natural way to do that. Similarly, you take a stream and you iterate it. So the iterated pattern flows. So a lot of these things merge into patterns, a big version of the language feature. Once you get past it, there are some new patterns now. So one of my favorite patterns is, then you could say we can use newer patterns like for example, execute around method pattern. So essentially, you can use lambdas or functional patterns. So one of them is called the execute around method pattern. Execute around method pattern says, I have a piece of code, but around that code, I have pre-op and a post-op. So this becomes very easy for you to model this in your code as a execute around method pattern. For example, if you look at languages like Python or Ruby or many other languages, you open a file, but you never close it. So here's an example in Ruby. File.open and you say filename and you say do file and you say end. And here you say file.something. Notice you never do a close. Why not? Because when you leave the block of code, the close happens automatically. This is called the execute around method pattern. This is very powerful pattern because you don't have to worry about oops, I forgot to close the resource. You just acquire it. When you leave the block of code, it's released. So that reduces the burden on you. But we have used this in Java for a long time. You just don't realize it. Where did we use this in Java? Years on years. Synchronize. Object. Remember that? You acquire the lock when you say synchronize, synchronize. But do you release the lock? It happens automatically here. That's your execute around method pattern. But this was only for synchronize implemented in Java. But what about my own code? That's what this is doing. So these kinds of patterns and what are we passing to it? Oh, that's a lambda, by the way. That you're passing there. So you can do similar things in Java as well to implement this execute around method pattern. So some patterns simply hide away as features of the language. Because the more capable of languages, the fewer patterns you will have. And then as a result, we have some newer patterns that we could use. Like this one, we can start modeling, for example. So it becomes very powerful as well. Awesome. Please. Beautiful, beautiful. So bottom line is this, the code is a mess. I didn't write it. Somebody gave it to me as we do in companies. They didn't leave any tests behind. But I want to really refactor it, make it maybe functional style. What can I do? Very reasonable question. So this is where we need to rethink. Tooling can help us a lot. So we can rethink about it. So we don't do this enough, but I think we can. This goes back to your earlier question. What can we learn from functional languages, other languages? So people who are programming a language like Haskell and Erlang, they use a tool called QuickCheck. And a QuickCheck is a tool that would take a piece of code and run through various combination of tests on it. And the good news is QuickCheck is available for Java now. So you can run QuickCheck on your function. You will run through a slew of tests on it. Hopefully it doesn't break because your functional style code is messy but correct. But the good news is now you have tests. You didn't have to write them manually, but you can write QuickCheck for it. The key is this, right? The key is you nailed it. And that is tests are safety net for refactoring. There's no way around it. So the question is not, can a refactor without test? Question is, how can I get the test without losing my life? And the answer is, find tools like that. The other thing you may essentially do is there are some tools like this which use AI to generate the test for you. But at the bottom line is, you've got to have tests. But it doesn't mean you have to write the test. You just need to get the test. And then once you do, you can refactor and see if it's working. And that can be a way to get around it. Please, you are beautiful. I love it. I love it. So functional, this is a term I try to use. Functional style is equal to functional composition. Very, very careful. Functional style is functional composition. It's the pipeline that we saw. The pipeline is nice. The pipeline is not enough. Functional programming is equal to functional composition plus lazy evaluation. Without laziness, you're not doing functional programming. You are getting functional style. Why is this important to keep in mind? So I'm going to throw a little slogan here. I'm going to say polymorphism is to OOP as lazy evaluation is to functional programming. If you're saying, I'm doing optional programming, I'm like, where's polymorphism? If you're not using polymorphism, that is object-based programming, not object-oriented programming. So polymorphism is the key to OOP. Lazy evaluation is the key to functional style. But there's also a beautiful question. This also leads to something as an implication. And that is, this ties back to one thing I wanted to talk about, but then, but I'm glad you brought it up, functional programming relies on lazy evaluation for efficiency. So if you don't have lazy evaluation, all you have is a functional style. It's nice to see, but you don't want to use it if it's a large collection. You're going to lose on performance. And what good is a beautiful code that runs slow? We're not going to be using it. We say, that's a nice idea. Thank you, but no thanks. I've got real work to do. But lazy evaluation relies on purity of functions, also known as immutable, right? Immutable bitty, immutability for correctness. So this is where it gets very tricky. When people say, in functional programming, you have to honor immutability. That's not because it's fashionable. It's because, look how cool we are. We're writing immutable code. No, it's an existential crisis. If you don't honor purity of functions, your code will give you wrong results. If you want wrong results, you can get that by writing code in C++. You don't have to write the code in other languages, because C++ gives you performance with no accuracy. But you want correctness first, that you care about. So if you want correctness, you need to honor purity. That's because lazy evaluation is not optional. It is an existential crisis for functional programming. You want really performance. It's got to be lazy. So functional programming relies on lazy evaluation for efficiency, and lazy evaluation relies on purity of functions for correctness. So this is why if you are programming just to get a nice flow and reduce the complexity in code, with regard to performance, you can do functional style. But you want to really go for functional programming, because that really comes from having a laziness. You don't have a choice oftentimes. Some languages like JavaScript give you only functional style. You may have to use third party libraries to get lazy evaluation. Otherwise you don't have laziness. Languages like Java and languages like C-Sharp, even though they are not traditional functional programming languages, they are still hybrid functional programming languages. Why? Because both Java and C-Sharp give you lazy evaluation. That's the behavior, right? I was going to say default behavior. No, that's the behavior. That's the only way it behaves. Like your streams are always lazy. You don't have an option to change that. That's the way it works. The language itself has nothing. The language is a bunch of syntax, and semantics put together. So if you were to write your own stuff, if passing lambdas around, lambdas are lazy. It depends on when you evaluate it. It doesn't force you to evaluate at any certain times. It's baked into it. No difference. There's no difference. It's just the libraries. They also evaluate laziness. That's all. It's lazy in other ways, but it doesn't mean you have to have laziness everywhere. But with lambdas and functional pipeline, it is lazy, as simple as that. Yeah, that's what you're saying is. In Java, you don't have an option to be lazy. It is lazy. Streams are. Streams are. Yeah, absolutely. Yeah, it's hard to make it work. We don't care about the language, right? It's lambdas and functional pipeline where I vector defer, but you can go with that. Your goal is not for laziness everywhere. No, I don't want to. I want laziness where it matters to me. I don't want to boil the ocean with it. Where I like functional style code, I want laziness with it because I want efficiency. That's all I care about. I don't care about what else you can do in the language because I don't touch those features. That's why I differ from purity, right? Purity can take us to extremes, and then we throw away good things because of that. I want to be practical. You're writing code, mind your efficiency for the code you're writing. If you're writing the code in Java, you get it for free with no effort when you write functional pipeline. And if you're using something else, evaluate that. But you get efficiency in other ways in an imperative style language as well. But you got to trade that efficiency to, that's true in almost any language where you're using, right? You're using the structures given to languages. You don't use something that you don't have as simple as that. Yeah. But that's a distinction I make. Is that laziness really is a essential part for me to qualify it as a functional programming. If you don't have laziness in the code you're writing, and if it's doing an eager evaluation, then I would say that's not functional programming, that's functional style. Again, functional style is only when you're using functional composition, right? Otherwise it's not, it's imperative. And if it's imperative, I don't care, lazy or, you know, eager. It's not karma at that point. Did I answer your question? A little louder, please. Yeah, you have to be careful about it. But the problem also is it's semantics, not syntax. So you may look at the code all day long, you may not realize sometimes whether it's lazy or eager. So you kind of have to know the semantics. If you don't know the semantics, you could be walking away with the wrong understanding of the behavior of the code. You can go either way. Yes, please. No worries, no worries. So in Scala and Kotlin, you have the option to select when you work with the collection of data, you can say go eager on it or you can go lazy on it. The syntax never does lazy or eager. Syntax is just a way you express it. Not to my knowledge. You are probably confusing different use of the word lazy where variables are evaluated lazily or not. That's a different concept than functional programming. That's just differing valuation of a variable's values. That's not what I'm referring to here. One more question. Yes, please. Huh. Beautiful. Right. Yeah, I'm sorry. I don't write code with bugs, so I don't know. So there are two answers to that. Yes and no, yes and no. This is where the familiarity versus unfamiliarity kicks in. When you're unfamiliar with something, fear kicks in. Oh my gosh, what do I do when I go into this alley? It's dark, right? That's okay to have those fears. So there are two answers for it. The first answer is you need to understand the semantics because if you understand the semantics, you know, if you put a breakpoint, it's gonna hit the breakpoint. It just won't hit the breakpoint now. It'll hit the breakpoint when it's evaluated eventually, right? So you can debug the same way you debug code. If I ask you, can you debug multi-threaded code? You're like, yeah, well, it'd be called. Now, when it hits that point, same concept here. But there are two things you can do. If you break those functions into smaller functions and you should, you can unit test those functions. So if something is not working, why do you wanna debug a stream when you can just debug the function that you are using inside of it? That's one answer. But the other answer is, this is where it becomes really interesting, is if you use tools like IntelliJ IDEA, in IntelliJ IDEA, when you go to the debugger, there is a stream debugger. If you ever had a chance to look at it, take a look at it. It's a little squeaky that you'll see in the bottom. You click on it, it'll open a window and it will show you the execution data of a stream laid out. So you will see the original collection. Then you'll see a next column, result of the filter, a third column, a result of a map, and a fourth column, result of a reduce. So you can just read through it and say, oh, that was stupid over there, I can fix it. So you don't have to debug because it visualizes the stream for you. So that is something you can do. So the key is, you can understand the semantics, you can write unit test on smaller pieces of code, you can use the visualizer. So there are techniques available to reduce the burden. You can also put the most famous. So my niece was going to college. She's in computer science. So traditional as a family, right? When a child goes to college, everybody has to give an advice. So it was my turn. So you said, Uncle Venkat, I'm going to college, I'm going to be in computer science. So I went to her and said, let me tell you one thing, it's okay to use print tag. So absolutely, right? And put a peak. And the peak shows you what the output is. Debug to your heart's content. Just don't put that into production. That's all it is. That's all I have. Thank you, folks. Thank you. Thank you. Thank you.