3 Simple Ideas From Functional Programming To Improve Your Code

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
python is not a functional language in fact everything in python is an object but you're doing yourself a huge disservice if you don't know at least a few things about functional programming there are many things we can take from functional programming to make our code easier to maintain and easier to test so today i'm going to cover the three most important takeaways from functional programming or actually from the paradigm it belongs to and show you a few examples of how you can apply them to your own code but if you truly want to write great software you need to think things through before you start writing code i've written a guide to help you with this you can get it at ion.codes design guide it contains the seven steps i take whenever i design a new piece of software if you make a mistake at the start of the design process this can be very expensive to fix later on the guide is going to help you avoid that ion.codes design guide the link is also in the description there's a fundamental difference between object oriented programming and functional programming that goes beyond whether you're using classes with methods or functions in fact object-oriented programming and functional programming are part of two completely different paradigms imperative and declarative programming imperative programming focuses on how to execute it defines control flow as statements that change a program's state a developer that writes code using this paradigm specifies the steps that a computer must take to accomplish the goal it's also referred to as algorithmic programming sometimes most mainstream languages included object-oriented programming languages like c-sharp visual basic java and python were designed to primarily support imperative programming object-oriented programming is a subset of imperative programming that adds classes and objects to the mix declarative programming focuses on what to execute it defines program logic but not a detailed control flow an example of declarative programming is sql statements we don't care how it's done that's the control flow we just specify what we need excel is also a good example of declarative programming you write in a cell what you want the computed value to be you don't care about how it's done functional programming is a specific form of declarative programming from wikipedia in computer science functional programming is a programming paradigm where programs are constructed by applying and composing functions now before i talk more about functional programming let's take a look at an example a very simple example here which is a greeting class this has an initializer inside the initializer i'm getting the current date and time and checking whether we're in the morning in the afternoon or in the evening and based on that value i create an instance variable greeting intro that gets either good morning good afternoon or good evening then i have a greet method that takes a name and it uses this greeting intro to greet the person and then i also have another method to greet a whole list of people at the same time and then i have main function where i read a name i create a greeting object and then i greet the person now if this is something you really wanted to build i would normally not use object oriented programming but i'm doing this to show you the difference so when i run this code i'm getting something very simple so i'm entering my name and then it's going to greet me so as you can see i'm recording this in the morning there are a few things that are important when you're considering this class one is that the initializer relies on the date time package it creates a date time object and that means that every time you use greeting the result might be different another issue is that the greet method prints things to the screen and greet list calls the greet method so indirectly it does that as well because the methods in the greeting class directly print things to the screen they're hard to test and can't really be used by applications that don't print anything to the console but use for example a gui printing is an example of a side effect when you call the method it modifies something outside of the function the screen in this case in general a side effect is when a function or method relies on or modify something on the outside of that function printing something is an example but other examples are reading from and writing to a file or interacting with a database or another service over a network side effects make your code harder to maintain and make things harder to test because you can't isolate a function or method properly if a function doesn't have side effects and the return value is only determined by its input values so no random number generation or relying on outside things like the current date and time then the function is called a pure function as opposed to functions with side effects pure functions are easy to test and they're easier to use in different parts of your software because there are no outside dependencies if you want to write software that's easy to work on and needs to test take a look at your code and see whether you can turn some of your functions into pure functions if you focus on putting all those side effects in a single place they're much easier to manage in this particular case the greeting class prints things and it relies on the current date if we want to write tests for this class we would have to patch date as well as the built-in output which is a pain another way to view it is that combining for example printing with constructing the greeting message is a single responsibility violation that two different things so to make this class easier to reuse we should remove these dependencies on things like date time and then we should also remove the side effects like printing things to the screen instead of letting the greeting class create the greeting intro we could also supply it as an argument to the initializer so that means that this piece of code we can move it to a separate function and then we call that function instead in another place so what i'm going to do in this particular case is i'm going to my main function that's right here and then i'm going to paste this in here like so and now we don't need to self here there we go and inside our greeting class we're going to remove all this information right here and the initializer is going to be really simple so that's going to get a greeting intro like so and let's store that in an instance variable like so greeting intro that's a string and in the main function we simply need to pass the greeting intro as an argument like so you can also do this differently for example instead of defining the greeting intro here you could still define it in the greeting class but supply the current date and time to greeting so then at least when you create the instance of the class it's going to be predictable what the result is going to be the second thing i want to change is that greeting class is currently printing things to the screen so we preferably want to remove that side effect so instead of greet returning none we could let it return a string and then it's simply going to return the string inside the print statement there we go and now of course we also need to change greet list here so that's going to return let's say a list of strings so i'm creating a variable here list of string which initially is empty i'll show you an alternative way to doing this later on as well and then instead of calling greet like so we're going to append the result of the greeting to the greetings list and then in the end we're going to return the list like so by making these changes in the greeting class we've turned the greeting class into something that has no side effects whatsoever because it's completely predictable what it does depending on the input that it gets now of course we move those side effects to another place which is the main function so the main function clearly still has all those problems but as you'll see often in software design is that you're going to end up with a place where you're going to do all the dirty stuff basically that's where you do the printing where you do the input name reading part that i'm doing here where you're relying on low level or let's say changing things like the date and the time etc etc now at least all that dirty stuff that we're doing is in a single place in the main function which is good because that means that everything that this code uses which in this case is only the greeting class we can now test much more easily because we can now create a unit test that creates greeting instances and then test these methods really easily without having to patch anything or do anything complicated to summarize this your functions or methods should have return values that only depend on the provided parameters which is the case in the greeting class for example the greet method it depends on self which is the object and that object contains the greeting interval instance variable and the name and it returns a string and there is no other outside dependency same for greed list it gets self which contains the greeting intro and the greed method that it will then turn and call and it gets the list of names that it depends on and then it returns another list of strings secondly functions and methods should ideally return the same value if the parameter values are also the same and that's also the case here so we're not depending on the date and the time or a random number generator or something here to create different kinds of greetings if you provide the same argument value you're going to get exactly the same result always and that makes function a lot easier to test and finally functions and methods should avoid side effects you can't completely remove side effects because at some point you're going to probably print something to the screen or read something from a file or anything like that but when you need those things it's good to at least group them in a single place so that they're also easy to change out for something else and that the rest of the code that you're writing is not dependent on using those side effects now before i talk about the second takeaway from functional programming i want to show you an alternative quickly of the object-oriented approach which is using functions so now instead of having this class greeting i have a greet function that gets a name and a greeting intro and that returns this value so it does almost exactly the same as the reading class and we also have a greed list that gets a list of names and the greeting intro and that then returns a list of strings and you see what i'm doing here also slightly differently is not using like in the object oriented programming example where i used a variable here i'm using a list comprehension to call the greet function with this information for each of the names in the list and then i have split up main a bit i have read greeting which determines what the greeting intro is and i have read name which returns the name that the user entered and then in the main function i'm printing the greeting and then i'm also calling greet list just for testing so when i run this code i get exactly the same result and i'm also printing out a list of good mornings the second takeaway from functional programming is that functions are first class citizens they're not just groups of statements with input arguments and return value there are things that you can compose deconstruct pass to other functions and return as a value from a function if a function receives a function as an argument or it returns a function as a result it's called a higher order function let's take a look at an example in this example we can also benefit from using higher order functions at the moment in the main function we're simply passing values around we're calling read name which returns a result and read greeting which returns a result that we put into greet which then returns a result that we provide to print and greet lists it works in almost the same way with higher order functions instead of providing values to functions you can provide functions to functions for example what we could do in this case is that read greeting which uses the current date and time and then switches between good morning and afternoon and good evening we could also supply the function to the grid function instead of the intro as a string and the advantage here is that you can choose whether or not that function should be called because that might not always be necessary and then you can increase efficiency of your code and have more control over when what piece of code is called so i'll show you an example let's say i define a type called greeting reader which is a callable and that doesn't take any argument but it's going to return a string to us and as you can see read greeting is an example of a greeting reader function it doesn't get any arguments and it returns a string so then instead of providing the greeting intro here we can provide a greeting reader and that's of type greeting reader and here then of course i also have to change this because this is going to be the greeting reader and i have to call that function now inside greet and the same thing for greed list so i provide a greeting reader here and let's also specify the type and i do the same thing here there we go and as you can see i'm passing along the greeting reader function to the greet function which now also expects a greeting reader now the only thing i need to change in my main function is that i shouldn't call the function but i should provide the function as an argument there we go if i run this code it's going to do exactly the same all right ariane except now it's afternoon it's like just 1 past 12 but it does apart from that exactly the same thing and the fun thing is because we're now passing a function we have control over whether that function should be called or not inside the greet function so for example i could change greet function to check that if the name is ion then which is going to return progress and in this case i don't need to call this function i can just say bugger off because that's the default response apparently when the name is arya so when i run this let's try that again i enter my name ion should use the right spelling then you see i get bugger off another concept from functional programming is partial function application and that means that you create a new function that's based on an original function but with some of the arguments already applied and we can also use that here for example if i go back to my main function i could use partial to create a greeting function that already has the greeting reader function applied to it so let's import partial so that's from fung tools and then in my main function i'm going to create a greet function which is a partial application of creed and i'm going to supply it the greeting reader which is read greeting and now when i call this function here so instead of greet i'm calling the function i don't need to provide read greeting anymore so this is an example of partial function application so you get an object with partially applied arguments that is then a function you can call in different places and you can even take this step further for example greet list currently gets a greeting reader and then calls greet with the greeting reader so what we could also do is define a greeting function which is a callable that gets a string and that also returns a string so this is simply a function that takes the name and then returns the greeting and then we have the greeting function here so i'm going to change them to update the type greeting function and now it's going to call the greeting function here with just the name so this simply calls the function for each of the names in the list and now my main function instead of providing read greeting here i provide the delete function like so let's run this code and we get exactly the same result as before except now we're relying on partial function application to call these other functions here so hope this shows you that functions are really flexible and that you can do a lot of things with them now it doesn't mean you have to go all in on using higher order functions and partial function application everywhere because if you overdo it it might also lead to less readable code but don't forget these tools exist and that you can use them to design and organize your code a bit differently than you're maybe used to in imperative languages like python variables can be accessed or changed anytime you like in declarative languages variables are generally bound to expressions and keep a single value during their entire lifetime for example in excel you specify what needs to be computed in each cell one cell doesn't change the expression of another cell that would become a huge mess similarly in functional languages like haskell there are variables but by default they're not mutable once the value is set that's it though haskell does support multiple variables what's the advantage of having immutable variables well for one it solves many multi-threading problems where we might have multiple threads trying to change a single shared variable at the same time another benefit is that if we have a guarantee that a variable never changes our programs become a lot easier to understand and are also much easier to test let's look at a few examples i have very simple example here it's only a main function creates a list and then performs some operations on the list so the first thing that i want to look at is sorting so you can do sorting in a mutable way or in an immutable way here you see an example of a mutable sort so i take my test list which contains a bunch of numbers and i'm calling sort on that test list and this is mutable because sort changes the test list itself so when i print the list i'm going to get the modified list immutable sort is different and that's using the sorted function which is also built into python and that gets a test list and then creates another list the sorted list and this is a copy that's sorted but it doesn't change the original list so now i can print the original list here and it will still show me this and i can print the sorted list which is going to show me the sorted version of this let me run this to show you what i mean so here you see what we get so the first part is using an immutable sort so we get a new sorted list which is this one but we still have the original list but after applying a mutable sword the original list is now changed here you see also a disadvantage of using mutable operations like in place sorting that we have here which is that if you want to retain the original list and you want to print both of them you can't because you lost the original data so you can't verify anymore whether the sorting happens according to what you want it if we don't change the original list like what we're doing here with the immutable sort then it doesn't matter we still have the original and we have the sorted list so we have both and i'm printing both or if you still need to work with your original list for some reason you still have it so that makes it a bit easier setting up testing is also easier when you're using immutable operations for example in this case if you want to set up a property test to verify that the length of the original and the sorted list is the same this is very easy here because we have both of the values after we perform the operation if you use mutable sort you would need to make sure to make a copy beforehand and then you can still do the comparison of course but it's a bit of extra work an extra thing you need to think about when you're setting up your test and this happens everywhere in your code where you're relying on mutables because you may not have the original data so you have to make sure that you don't lose that another nice thing about sorted is that it actually accepts an iterable so that's what you see here on the screen so that means sorted actually works on other things than lists so if i replace let's say this test list by tuple so now we're going to have this something like this now the immutable sort still works but tuple doesn't have a sort function so i can't do this anymore so immutable sorting in that sense also gives you a bit of extra flexibility since in order to sort something we only need an iterable we it we don't care whether that's the list or tuple or something else i just want to quickly show you another example of mutable and immutable operation so it's not just for sorting but it works for other things as well so here i have a list of cards and suppose i want to shuffle this deck of cards now there's also here an immutable and immutable way to do it so in this case here is the mutable version of this so that does a random dot shuffle and then prints out the card so this changes the cards variable but if i use random.sample i provided the cards and i tell it to sample all the cards from the deck then i get a new shuffled card list and the original cards list is not changed and also here when i run this so you see we have our shuffle card i still have the original card but here after i do the mutable shuffle i don't have the original list anymore and also here random.sample is more flexible because it expects simply a sequence where a shuffle expects a mutable sequence so if i change this again to a tuple like so you see that random.sample can handle this perfectly fine but random.shuffle can't so immutability potentially gives you extra flexibility and it's not just for these simple structures like lists or tuples you can also use it for example in data classes so dataclass has a frozen option that's also really nice to make sure that your data doesn't change and then it also makes it a lot easier to write tests for that so what's the takeaway of this well if you notice in your code that you're changing variables all the time try to restructure it so that it happens less often can you turn some of those things into immutable structures instead and when you do that you're going to notice that your code is going to be much easier to maintain because things are going to be more separated and it's also going to be probably easier to read as well if you keep these three takeaways in mind while you're writing your code you're going to almost automatically navigate towards taking better design decisions if you want to learn even more about applying ideas from functional programming to your code you can do some pretty cool stuff with python's font tool package check out this video next thanks for watching take care and see you soon
Info
Channel: ArjanCodes
Views: 99,389
Rating: undefined out of 5
Keywords: functional programming, software development, software engineering, what is functional programming, functional programming tutorial, functional programming advantages, functional programming in python 3, functional programming vs object, functional programming explained, functional programming patterns, learn to code, computer science, videos for developers, how to write clean code, clean code, functional programming benefits, higher-order functions
Id: 4B24vYj_vaI
Channel Id: undefined
Length: 22min 49sec (1369 seconds)
Published: Fri Jul 15 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.