 So the next talk will be functional programming inside OOP. It's possible with Python by Carlos Bichavisensio. Hello, Carlos. How are you? Hey, good morning, or good afternoon. Good afternoon, Pierre. Where are you streaming from? Actually, I'm from Chile. Yes. Oh, nice. I'm from Argentina. Well, I'm from Ecuador, actually, but for some reasons I'm in Chile now. And how's the weather over there? Well, it's freezing cold, yeah. Oh, here we are a bit warm at least. Oh, right. Okay, I think we can add a presentation, and you can start when you are ready. Good luck. All right, so hello, everyone. Welcome to me talk about functional programming inside OOP. It's possible with Python. Here we're going to run into some concepts and facts about functional programming. And my goal is that you raise some curiosity about these topics and make the world a better place. And first of all, let me introduce myself. I've been a software engineer at Stack Builders for more than three years. Currently, I'm working on a project as one of the tech leads in Python and some React applications. Besides that, I collaborate with community engagement by organizing a Meetup and more events like last year's October Fest. Feel free to connect on LinkedIn and check out my past blog posts. In my personal life, I practice Kendo and Yaido, both Japanese martial arts and also a photography enthusiast and regularly post interesting pics on my Instagram account. But I don't consider myself a functional programming expert. I work with languages such as TypeScript, Ruby, Java, C and PHP in the past. I'm currently playing a bit with Clojure and Haskell. Stack Builders, there are a lot of Haskellers from whom I have learned a lot. We use also functional programming patterns in hybrid languages. For the record, I haven't used a for loop in a while, pun intended. And why functional programming? Okay, to me it has made my life easier. And let me explain some of the reasons. Compared with imperative programming, functional programming solves the problem in an easier and an efficient way like focusing on what rather than how, which is the declarative programming way. Divide and conquer by focusing on the implementation of smaller and testable pieces, also known as functions. Makes the debugger process easier, which takes 80% of the development time according to the recent memes and makes our code simpler, which compiles with the PEP20, the Zen of Python. And the code will be easier to test. And I will elaborate more on this at the end of the agenda. In a blog post from 2009, our friend Gidovan Rosum brought up about the origins of Python's functional features. Although he made functions first class objects in the first place, he didn't design Python as a functional programming language. However, due to its popularity, the users wanted to do more with lists and functions. So they started to implement their own map function and use a hacky way to build anonymous functions. Then in 1994, the higher-order function map filter and reduce were included in the standard library along with the lambda expressions. And naming variables, it's hard, right? So imagine naming expressions when building a programming language. The term lambda led to unintended consequences, causing the users to compare the syntax to other programming languages and raise more issues about the lack of advanced features in Python. List programmers can get a clear idea of this issue. Lambda expressions didn't have the reference to the outer scope, which was added in version 2.2. And from then, it remembers the references from the outer scope. Is that concept familiar to you? If you're thinking about closures, you're right. This is an essential feature of functional languages. Nowadays, fans of list comprehensions are larger than all higher-order function syntax and lambda expressions. And reduce was moved to the fun tools package. But it's still encouraged to study its syntax to learn how things work under the hood and the motivations behind them. As Gido said in this blog post, not having the choice streamlines the thought process. Am I already convincing you? Let's walk through the most important features of functional programming that I frequently use in Python. Take this example from Django source code from 13 years ago compared with the latest version. The implementation migrated from an imperative design using loops to comprehensions with mapping and filtering. An immutable object is an object whose state cannot be modified after it's created. Python managed the mutability of objects differently. Booleans, strings and integers are immutable objects. List and dictionary in the other side are mutable objects. And what's the benefit of having immutable objects? We have threat safety. No matter which threat is accessing the object, it is guaranteed to have the same state it originally had. Also, in OOP, we can have better encapsulation. We can trust that our objects won't change when passing them to other methods, and they can always be passed as reference. So we won't need to use complex techniques for copying objects. And since objects don't change, it's easy to track down the causes for some bugs, making our debugging process more efficient. Let's say that we implement a function that adds something to an object, an element to a list, and some integer to a value in the next example. So it is natural to think that after the execution of any of these functions, the value will be affected. That's true only for the one that manipulates the list, a mutable structure. If we inspect the ID, the identifier of the value, and the mutated object, we confirm that it is the initial object, the list. A different behavior happens for the function that manipulates the integer value. So let's print out some information. A different object is assigned to a value inside the function scope, and after we return, it didn't affect the original full value. Decorators. Probably many of you might be familiar with this feature, which adds some functionality to an existing function. This is also part of metaprogramming, because one part of the code is being modified by another at compile time, and the decorators were born because of the higher-order functions. Instead of creating a new function, we just create an existing function, executed and extended the implementation inside a new one. It is a function being called inside another function wrapper. In short, decorator uses closures. Let's see this example. We initially defined a function that increments the number plus one. Next, we defined a decorator, and returned the decorator inside the double increment, which applies the function of it, receives and does some extra logic. Finally, we can use this syntactic sugar with the add symbol to apply the decorator function. If we do some introspection in Python's compile code, we can still find our original function inside the closure object. Okay, let's move on into partial application. So this function is incredibly useful when we need to reduce the number of arguments that any function takes. Let's take a look at this example. So we have this function, getURL, that takes two arguments, the URL to be fetched and some user role. But instead of calling it with a repetitive role every time, we can simplify this as a new function with a known role, using the partial function. See these other useful examples. In this case, we define functions that will match strings against non-regular expressions. For instance, the animate matcher or URL matcher. Okay, lazy evaluation. So this is an evaluation strategy that holds the evaluation of an expression until the value is finally needed. This concept also prevents repetitive evaluations. The lazy evaluation was introduced for lambda calculus in 1971. With lazy evaluation, we can define infinite data structures and reduce the memory footprint because the values are created only when they are needed. In Python, we can make use of it by using generators. And what is a generator? Well, it's just a simple function with a yield operator. Then the execution will stop on that point and resume it whenever we need to generate a new value for the same function. Did you know that opening and reading each of a file's lines yields a generator too? In this example, the variable line is assigned from the lines of the generator F. Type annotations is one of my favorite features of Python. Last year, I presented an entire talk about the type annotations in Python. And to sum up, type annotations can help us to detect bugs at development time and increase the readability and maintainability of our code. Have you noticed that my code samples have type annotations? It's really hard for me to write code without types. I currently use this feature in a production project. And recently, it has become more popular among open source developers to provide type hints in their APIs. In our recent presentation, Github and Rosam said that the type annotations feature is still growing and it has learned some things from other languages such as TypeScript. The type checking tools are now easier to use and easier to integrate in your favorite editor. You have no excuses for not using them. You can take a screenshot of this slide and check out this article I wrote last year and my talk that I did last year about this entire topic. Structural pattern matching. This is a new feature from Python 3.10. I think there will be another talk in this conference about this topic while we follow it. But in short, if you have used C or JavaScript, maybe you are familiar with the switch statement. The difference is that it is used to compare between an object or expression and a literal. But Python's design is more a declarative approach that uses the type and the shape of the subject. Of course, it can match a literal, but it can also match patterns with values, classes, unpacking, nesting, and even we can use the if guards. See this example. Given a point which is too valuable, we can implement our match logic for the object 0, 0, 0, y, x, 0, x, y. Maybe we have two cases for the x, y, which is implemented with an if guard. And even we can use the underscore at the end, which is a value that doesn't match the above patterns. The underscore, for example, behaves as a wild card, and it is not the default case as other programming languages. You can use also as a part of a complex unpacking in this example. You can see that the last case is doing an unpacking of the receipt value. And the last one, well, it doesn't matter because it's a wild card. If it match, it prints this error occurred. So let's see another functional programming patterns. Let's start with Korean. Well, Korean transforms a function that takes many arguments into a function that accepts just one. And returns a function that takes fewer arguments. This is a key pattern of any functional programming languages. I won't go deeper into the details, since I'm not an expert in this field, but as a quick overview, I can say that besides styling preferences, it's a way to save some state inside pure functions. Have functions with partial arguments applied, and reduce expensive computations. This is like the, you can see in the slide, like the definition of Korean, the mathematical definition of Korean. But let's review a quick example. Let's start with this function that sums up just five values that received as an argument. We can convert this as a function that returns functions with partial applications of its arguments. Then at the end, we can have this C5 function that only takes one argument, and we can pass just one argument to every of the functions. What about having something like this, a decorator that is easy to use for, I don't know, undetermined number of functions? Okay, so please don't reinvent the wheel. In this section, I share our references in the slide, where there's a neat implementation of query as a Python decorator. There are also some other open source Python packages that implement this functionality in their libraries. Let's move on into composition. Remember that in Linux, we do something like this. You may know that the vertical bar operator is called pipe, and it gets the result of the previous execution and passes as an argument to the next one. So composition is a similar concept but with the reverse order of function executions. It allows you to build more sophisticated functions out of simpler ones in an easy and readable way. There are programming languages such as Haskell, where the composition is part of its core, and you can do something like this. Pretty easy, right? But there's no native way to do function composition in Python. So if you need to compose two functions, you can write something like this. But what if you have n functions? Then you can write a piece of code that looks like this. And what happened here? Well, we're using reduce with the same name that most functional programming languages name this function, fold, to iterate and accumulate the applications of a list of functions received into a single one. So we can use it like this. And let's say that we have three functions. For typical HTML tags, then we can build a new function with a composition of these three in order. There are more functional programming patterns that we can implement in Python. An interesting one is monad for error handling. This will make the presentation a bit longer, so I'll try to write something about this in the future. Oh, finally, let's talk a bit about testing. So code that is hard to test is not a good code. That is something that your aims wrote. So if you're using PDD, test-driven development, or WTA, write test after, you know that tests are an important part of our daily projects. Writing pure and small functions with no side effects simplifies a lot the complexity of writing tests. Our code will be comfortable, reusable, predictable, and easier to test. Using an imperative approach to write our tests, we need to do everything in all the steps and create mocks in order. Otherwise, the flow will explode. On the contrary, the clarity paradigm is stateless, and we don't need to care about the order of the big picture of our logic. Just test our isolated pure functions. There's another interesting quote about the moving parts of a code. Object orientation makes code understandable by encapsulating the moving parts. Functional programming makes code understandable by minimizing the moving parts. Michael Federer wrote this one. What are the moving parts? Here are the state mutations. We won't deal with them in functional programming as object orientation does by encapsulating them. And yes, we reached the end of our journey, none of the road. I hope that today you feel curious about these concepts related to functional programming and why they will make your life easier, at least your programmer's life. There are a lot of interesting features that Python offers in the Functools model. So please go check out the official documentation of this model and play a bit with them. As you can see, Python is something like a hybrid language. It is designed to be an object-oriented language, but with an interesting set of functional programming tools that you can use, mix, and improve the way you write your logic. And of course, learning pure functional languages will change your mindset in the long term. All the references are included in my presentation. As you can see, you can see this presentation and download it into my profile. And yes, if you have any questions, feedback, suggestions, feel free to reach out and connect. Thank you for your time and attention. Hello, Carlos. Thank you so much. Really nice. You're welcome. Okay, we have time for some questions. The first one is, have you used dry Python lambdas? Not. I think that there can be a Python package or library. I haven't used it in the past, but I'll go check it out. The next one, what would you like to see from other functional programming languages in Python? Well, as I said before, the type annotation system is pretty good, pretty useful for my experience at least. But there's a lot of room of improvement in this area. There are some things in other languages such as TypeScript, for example, or Haskell, where the defining types and the type system is a bit stronger, even though Python is a strongly typed language. Well, that, for example, and there are some other things that I talk about in my presentation, for example, curing, it will be great to have this unimplementation, a native implementation in the language. I've been playing a bit with Rust, and I find it quite interesting the ideas they propose. The next one, does functional programming concepts are more performant than regular loops? Well, that's a really hard to answer question because there is a lot of debate of performant for functional programming. Some people say that functional programming is not as performant as regular loops, for example. There are some benchmarks that prove that. But in the other hand, it depends also on the project. If your project doesn't rely on expensive computations, maybe you can sacrifice a bit of it in favor of readability of your code and maintainability in the learn room, it will be easier to extend the code that you have instead of having an imperative design. Okay, and the last one is, you can use both object programming and functional programming in Python. What's your opinion combining them in some way? Well, I think it's inevitable to combine them because, as I said before, Python design is object-oriented. Everything is an object in the language. It's impossible to just not use it. The project that I'm working on, we have classes, but it's data classes, for example, and some other object-oriented patterns. But we try to use the functional programming philosophy inside them. For example, creating methods as pure functions, easier to test, try not to depend too much on the state, things like that. Combining them, it's easier to test and it's better on the learn room. I would like to see maybe more expressive lambdas. Me too. That would be nice. Okay, for now, those are the questions. If there are more questions, we'll print to ask in the breakout room for Optimal, breakout one. And that's it. Thank you so much, Carlos, again. Thank you, Santiago, and thank you to the conference for the opportunity. Bye. Bye-bye.