Practical Functional Programming in Dart & Flutter

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
while Dart is in its core an object-oriented programming language that doesn't mean that you're stuck only with that Paradigm in fact Dart is something called a multi-paradigm language and functional programming makes your code easier to test and reuse and also makes it less error prone with dart it's easy to start introducing practical functional Concepts into your code in a reasonable amount and this way you reap the benefits of functional programming while not not confusing others and yourself with how your D code is [Music] written hello welcome to reso codra where you are getting prepared for real app development so that you will get freelance clients or a job and be confident about the apps you build so subscribe and hit the Bell to join us on our quest for becoming in demand flutter developers so in this tutorial we're going to look at functional programming from the very basic Concepts which probably many of you even intuitively know if you have been uh programming in Dart even if you have not been looking specifically into functional programming but still it's good to go over them and then we're also going to get to the let's say intermediate functional programming Concepts which are possible in Dart and be sure to check out the written tutorial from the link in the video description where you can find all of the code written in this video and overall go through this lesson at your own pace so to get started we are going to look at two approaches to writing code in Dart which is possible just in Native Dart without any additional packages so here we have an imperative way of writing code and a functional way of writing code you are most likely all familiar with the imperative because this is what your Hello World app tutorials are teaching you basically just create a for Loop which will sum the contents of the list so we need to create an integer for the sum where the sum is going to be stored then we create a for Loop an iterative variable called I which we increment and we simply add the value the integer at the place in the list at the index I do the already add it to some so what are we doing here well we really need to think about what the code needs to be doing what the computer needs to be doing step by step in order for us to be able to sum the contents of the list we as programmers we are really interested only in the end sum but with imperative programming we need to also declare this iterative variable then increment it worry about when to stop incrementing it and so on and so forth so we are really diving deep into the in know workings of the program which in this case of course is fairly simple it's just a simple for Loop but you can see that if you are in a more complex code base this kind of only imperative programming mindset is going to limit you and also introduces a lot of ways where box can enter into your code however with functional programming the story is different here we again have the same list but this time we are using a functional approach not imperative which means that we do not need to create any iterative variable there is nothing like this here we just need to call list. fold which is something like a for Loop in the functional realm which will iterate basically over every single element of the list and this fold accepts an initial value which we make to be zero just like initially sum was zero here and then this initial zero gets added to because previous is initially zero and it gets added to one then it adds two three and four and just like in the imperative also in the functional approach we in the end get the total sum of the individual elements of this list so notice here that in the functional approach we do not need to worry about any iteration ourselves about managing this for Loop it gets basically managed for us and also we do not need to create a mutable variable for the sum but it can be immutable it can be final we cannot change this sum later we cannot increment it because it's final right so this makes our code less error prone because we cannot mistakenly somewhere 50 lines later if we have a long code base of course decide to well increment sum or change it in any other way and this is of course just a very simple example that perhaps many of you already know intuitively but this is really the core of functional programming and it's great that we can very simply use it in Dart and with this basic knowledge we can now look at other examples of how functional programming can help you write better Dart code let's look at another imperative example here we want to assign character count to strings of course you can call do length on any string AB C and just call length and this will give you the character count of that particular string but for some reason perhaps we are way too lazy to call length always we want to have a list that bundles this length information inside of it so at the star we just have a basic list of strings very simple Dart is awesome and in the imperative approach we again need to create a for Loop where we are going to be changing and adding to this car count list this list is of type record containing string and integer record of course is the Beloved feature of Dart 3 where you can basically create type save Dart objects on the fly so this simple record object is going to hold string which is the original string for example Dart and this integer is going to be the length and so inside of this for Loop we add to this car counts list the unchanged string and then also the string length so if inside of this main method we call imperative one or let's just change it to imperative and also in here we are going to print the C car counts list we see Dart which is four characters long then is two characters long and awesome which is seven characters long but now let's say that in addition to just creating this character counts list we also want to filter it where it's going to only contain the character counts for Strings longer than two characters so in this imperative approach we need to go inside of this for Loop and write an if statement where we're going to say if the strings at the index of I dot length is greater than two and only then we want to add it to the character counts list otherwise we're going to leave it out from that list so now now when we run this code again we are going to see only Dart and awesome the is string is left out because of course it's precisely two characters long but we add into this list only the strings which are more than two characters long so what's happening here if we want to change this code just a tiny bit we need to go inside of this for Loop inside of this whole function Orient ourselves inside of this inner workings of the code about what the iterative variable for the for Loop is called which in this case is I and so on and so forth just to add this simple functionality again here it's very simple this code is here just for the sake of an example but you can imagine and I'm sure if you are a d developer for quite some time you have faced code bases is where if you are required to go inside of an already written function sometimes it makes you pull out your hair because it's just so difficult even when there are tests written for everything still if you need to understand the whole function first before adding any code to it and you need to understand the inner workings of it well that makes your coding experience ni not all that fun but let's look at the functional approach to this down here you can see how we can create the character counts list in a functional manner first without the filtering by the length of the string that it needs to be greater than two so again we create a list of strings Dart is awesome and then instead of creating a for Loop and mutating the character counts empty list one by one by adding each and every element to it as we go through the for Loop we instead call strings. map and I'm sure that if you are a d developer for any amount of reasonable time you have already used this but perhaps you have not thought about it that much and we are mapping this list of just simple strings to the list of record string bundled with its length very simple and easy so let's now call the functional implementation of this code and we see that we again print Dart is awesome and the string lengths right next to it but what if we want to add this filtering to this functional approach as well it's as simple as before mapping this list of strings first calling do where on it where element do length is greater than two and let's actually rename this element to string if we run this now the functional approach will also not print out the is string because it's just precisely two characters long and notice What's Happening Here we do not need to go inside of the already existing code in this case just this for Loop for the imperative approach we don't need to worry about the internal workings of the code which was written previously we just simply come in and add new functionality on top of the previously written code but we don't need to go inside of that previously written code we can just compose functions you don't need to worry about the inner workings if you write everything properly you can just create separate functionalities and sort of add them up together and you will end up with code that is easier to write and easier to read like tell me that this is not easier to read than this for Loop monstrosity and also obvious ly the functional code is going to be easier to maintain and now of course here we are dealing with your regular List wear and map functions which all of you if you've been programming in art for some time you have used these functions already this is nothing new but you can absolutely create your own functions that will work in just does the same way and your whole code base not just your list operations and map operations but your whole codebase will be able to reap these benefits of functional programming moving further let's now take a look at how you create class hierarchies in object-oriented programming in the usual way and then also how you can utilize algebraic data types which is more of the function programming approach to doing things and with d version 3 this is absolutely simple and possible to do now this code which I am showing right now is taken from an official Dart language medium post but I have made it into an actual Dart code because over there in that Medium post it was just total pseudo code which did not even compile remotely but now it compiles as proper Dart code so if you're wondering that hey I've seen this code yes you probably have if you've been reading the official article for when the art three came out so we have a very simple class hierarchy here we have an abstract class recipe which contains the time it takes to finish this recipe the temperature at which this particular thing which the recipe is making should be baked at and then the ingredients which is just a list of simple strings then also it has one method which is a member function of course of the class called bake and if we want to create a concrete implementation of this abstract class recipe for example for making a cake we're going to create class cake add the proper time temperature and ingredients and then implement the bake method of course this bake method doesn't really do anything it doesn't return anything it's just a pseudo implementation but hey you can imagine that this kind of works and then if we want to make cookies we create another subass of this abstract recipe add other ingredients change the time and temperature and then provide yet another implementation of the bake method which also rotates the cookies and does all this crazy stuff of dividing the time and multiplying whatever it does it's just simply a different implementation of the bake method than for the cake this is how you usually write objectoriented code there is nothing special about it you've seen this a million times but let's look at the very same functionality of this class hierarchy implementing in the functional approach using algebraic data types here we again have the main class called recipe which contains the same data so time temperature and list of ingredients but it's not abstract this class is sealed which is again a keyword coming from Dart 3 notice that we all also do not have the bake method in here we actually don't have any methods inside of the classes at all neither in this sealed recipe but we also don't have any methods inside the concrete implementations being cake and cookies inside all of the classes we just hold the data and the data is the same as in the objectoriented version exactly the same way to call the super Constructor and everything but we just don't have any methods in here why is that well because we are going to perform all of the operations all of the logic totally outside of any class this is not a method because it's not a member function this is simply a top level function at least in this case and instead of implementing the different imp mentations for baking the cake and baking the cookies inside of the respective classes sub classes we implement the different functionality inside of this top level bake function based on Switching through this recipe and in case it's of type cake we bake the cake the usual way just as in the object oriented approach and in case that we are baking cookies we again have this different implementation the end result of the functional approach and of the object-oriented approach is the same the cake and the cookies are going to be baked in exactly the same way but the code looks different and the principles behind writing the code are different because here in the algebraic data types functional approach we have a hard separation between the data and the operation on that data the data is held in these classes and the operation on that data is separate it's just a simple function and of course the dart three features make sure that we are save here we for example cannot forget to check the case for cookies if I delete this we're going to get a red squiggly line saying that that type recipe is not exhaustively matched by the switch cases since it doesn't match cookies right we should try adding cookie case so if I add it back we're fine again this exhaustive switch is a feature of the art three of course and it's possible just because of this sealed keyword sealed classes need to be contained within one library for example within one file as we are doing here I cannot be extending this recipe from totally another library from another file but only within here and that's because the dart compiler can then figure out for example this thing if we are checking for every possible subass of recipe inside of switch but what is the main difference here between functional approach and objectoriented approach here this bake function is is a clean function that's a name used often in functional programming for describing functions which depend only on their own parameters and the only way they output something is through their return type in this case we have void but you know you can imagine we would have some return type here other than void but it doesn't really matter in this case what matters is that this bake function is a closed system nothing gets in except through this recipe parameter and nothing gets out of here except for the return this makes functions very easy to compose and test because you know precisely what's going on you don't need to go looking into the source code especially if you have a complex 50 line function before you try to test it just to find out what's going on in there everything is contained however in the objectoriented approach the story is different here we are actually in each and every of these bake method implementations not using just what is passed into this method actually nothing is even passed into this method we are using the class members we don't get them from the parameter list of this method we get them from the class where this method is contained here it's pretty simple nothing to really worry about we are dealing with simple classes but when you have complex class hierarchies with many members in some cases you can end up with an entangled mess that is hard to test and when you test it you need to provide a bunch of different marcks and know when exactly to initialize those marcks when to reset the data inside of those mocks and all that sometimes it can really be a mess other times it can be perfect but sometimes when you need to have a cleaner approach to writing code using this functional approach where data and operations are separate and you're are dealing with clean functions instead of these unclean methods getting data from wherever is beneficial that is not to say that this object or Ed approach is bad it's not but sometimes it's better to have this functional approach now that we have looked at all of the things which D Language by itself provides to us especially starting from the version three in order to write more functional code let's also take a look at a package called FP Dart and precisely on how to do error handling with it and what benefits it provides in that area so let's first go into our pspec yammo and you want to make sure that you have a dependency here on FP Dart current version is 1.1.0 but this functionality is almost 100% not going to change even in the future versions again all of the code and dependencies are also available in the article to which you can get from the link in the video description and let's say that we have an enum grade of course grades at least in the US can be a b c d and f and we also want to be able to parse a string to a grade so we create a static pars method inside of this enam which first will make this grade string to be uppercase so that whether we pass in just a or an capital A it's always going to result in the same output of grade A and if we pass in some jibberish we are going to throw an argument error inv valid grade and then uh provide the gibberish which was inputed fairly simple right this is just basic error handling basic Dart and now in the main function we try to parse the string a into this grade enum and then we pass it here to somehow use grade which currently is not implemented but let's say that the implementation will be that we print the grade if we run the code now we see that the output is grade A as expected but what happens if we input some gibberish like this try to run this now and oh no we get this exception has occurred thing and our code crashes and nothing works that's because we do not have the try catch around this parsing code and the worst thing is as of right now unless we remember manually to add this try catch around this uh parsing code we are now going to be notified about the need for this Tri block by the dart compiler we're not going to get any red squiggly lines in our vs code there is only one way to find out about this missing TR catch block and that is at runtime when an invalid character sequence is inputed into this pars function so let's just add on argument error catch e and print out e do message so now when we run the code trying to parse this gibberish everything's going to work sort of at least our program will not crash but uh we need to remember this in our own head and that's not very good especially if you have large codebase you're just bound to forget about some little thing like this about an argument error lurking somewhere deep in your code base a functional programming principle is that if something can fail we want it to fail at compile time and not at runtime using exceptions and this try catch flow is precisely the opposite of the functional approach because here everything fails at runtime and not at compile time so what can we do well we have already added the FP Dart package as a dependency for this Pro project so let's utilize a class called either from it if we take a look at either so let me just write either and go to the implementation we can see that it's a simple sealed class well at least in its principle it's simple here you can see that it has a bunch of mixings and everything like that and various methods like fold right fold left fold map and all this craziness which is very useful for people who want to go deep into this functional programming Paradigm but the perfect thing about Dart is that you can use just a bunch of things from the functional programming Paradigm the rest of the code can stay fully objectoriented and here in our case we do not want to worry about any of this useful but still craziness which is here present in the either type we just want to fix our error handling very simply so what can we do well this either class which is sealed has two sub classes right you see right extends either and then also similarly left which also extends either the subass right inside of eer is always used to convey the successful output of a function and the left subass of either is always used to convey the error and we have already seen how to work with sealed classes in this tutorial but FP Dart and this eer type has some helpers to sort of speed up this work with the either type so first things first what do we want to do here instead of returning directly grade from this pars static method we want to return either string and grade as you can see the left is of type string and the right value meaning the correct value is of type grade now we're no longer going to be returning just straight up grades but we need to of course wrap them up in either but not just directly in either of course but in one of the sub classes so we want to wrap it in right and this right Constructor accepts a value of type grade so it's going to be grade A and this would work but actually the usual way to work with either is not to call the Constructor here but instead a helper method which is the lowercase R for right and this is the usual way you're going to see the code written with eer but as you can see if we look at its implementation this helper instantiates the right subass of eer so let's do that for all of the other grades as well like this and now we no longer want to throw an argument error but instead we want to return left containing this invalid grade string so what have we done here well we have just unified the correct output with the error output for this pars method now there are no longer two data flows for the exceptions which we need to use the tri cat blocks for and for the correct output value everything is Unified into just this return type and this is awesome because now we of course can remove this try catch but now we can no longer possibly forget about checking for this error because gray. pars doesn't return us Gray but instead an either of string and grade and we just cannot pass this directly into the somehow use grade function which expects just pure grade we get an error saying the argument either cannot be assigned to the parameter type grade that's true and in order to get to the actual grade which we want to pass in here we need to use our trusted switch the exhaustive switch which works again because either is a sealed class as you can see here let's actually rename this grade to grade either and now we want to switch on this grade either and in case it's left which is just the regular name for the left subass of either the value inside of this left sub class we're going to assign it to final L and what do we want to do here well we somehow want to handle the error so let's just say print L and in case which we again need to check because we are inside an exhaustive switch which currently is not exhaustively matched so to match it exhaustively we say case right and the value of right which is of type grade will be passed into final R for right right we're now going to somehow use grade which in this case grade is this R awesome so now when we run this code it again says invalid grade makes sense if we pass in a valid grade let's say C we're going to C grade. C but as opposed to the usual error handling now we are forced by the compiler to actually really handle the error we cannot just simply forget about it somehow it's impossible to forget about airor handling when you're doing it in this way using a sealed class in this case the either sealed class but of course the FP doart package being FP Dart has a simplification for this either type which we can use instead of this switch statement which of course switch is pretty simple itself but we can simplify it even more so instead of writing this code we instead can write great either do match and here for the left value L we want to print L for the right value R we want to somehow use gr and pass in R and as you can see this is shorter than the switch statement but it does exactly the same thing so we can now delete the switch statement and run the code and it's going to work in exactly the same way so now we have gone through the basics of practical functional programming in Dart and also how to use it in your own apps especially this either type is very very useful we have not looked a lot lot into the FP doart package and there is much more to it than this either type so in the future I would like to create a tutorial focusing more on the FP Dart package itself now that these basics of functional programming are out of the way so if you do not want to miss that next tutorial which is incoming you really should subscribe to this Channel and also hit the notification Bell so that you will be notified about when that tutorial comes out and also to go through this tutorial at your own pce once again and to get all of the code we have written here check out the written tutorial available from the link in the description so if this video helped you give it a like keep an eye out for the upcoming tutorial so make sure you are subscribed and see you in the next video [Music]
Info
Channel: Reso Coder
Views: 11,245
Rating: undefined out of 5
Keywords: resocoder, tutorial, programming, code, programming tutorial, flutter, flutter tutorial, dart functional programming, dart fp, flutter functional programming, flutter fp, fpdart
Id: 8U2NH4fEmSs
Channel Id: undefined
Length: 37min 12sec (2232 seconds)
Published: Tue Dec 05 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.