#12 - Dart Functions - Anonymous Functions, Positional & Named Parameters, Lambdas, Closures, Scope

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what is going on everyone i'm wicked welcome back to my dart from novice to expert complete course in this tutorial we're going to hop on the flatterly train and move over to the next important station of our dart language tour and that is dart functions so without further ado let's get right into it beforehand though i want to send a token of appreciation to everyone supporting me as official youtube members especially to diana and michael aka aza on discord if you want to become a member all you have to do is to click the join button right next to my channel and pick your desired membership having that said let's continue with our tutorial now over the last tutorials we learned that everything in dart is more or less an object instantiated from its own class that is because dart refers to itself as being a true object-oriented programming language and since today we'll be talking about dart functions you need to know that dart functions are actually as expected objects objects having a type a class from which they're getting instantiated this type is called function and can be found in the core libraries of dart we may conclude from this that the function type similarly to integer double string and list is still a built-in type as we learned from previous tutorials since functions are also objects this means a couple of amazing things you can think of a function as being an integer for example since at the end of the day a function just like an integer is an object therefore this means that first and foremost you can assign a function to a variable now i'll assume everyone already knows what a function is for demonstration purposes we can create a sample one right here with a single argument a returning an integer type with the value of a as i said let's assign it to a variable now i want you to pay a little bit more attention to what i'm going to show you you might be tempted to assign this to the variable this actually means that the returning value of the function will be assigned to the variable in our case the value of our a argument we don't want that we actually want the function object we created to be assigned to the variable so we'll only have to use the name of the function here but fixing the name of the function with parentheses will actually call the function now the variable function object holds a reference to our first function object it's also important to know what the type of this variable is what do you think what you'll see is pretty interesting as the type of this variable is not only the function type but rather the types of the entire header of our function containing the return type the function type and the parameters type for now it's quite complex but you'll get used to it during this tutorial so we established that we can assign them to variables and since you can do that you can also pass a function as an argument to other functions just like with any other variable for example if we create another function called second we want this f argument to have the type of our created function so we'll just have to write that inside what we want to do is to actually call the function we passed as a variable and print its output so how can we do that well we can call the function a variable is pointing towards by writing variable dot co or even simpler just by using the default call parentheses on the variable don't forget to also set the a parameter of our argument function actually we can also send this as an argument to this function and use it directly just like this now if we run the second function we'll notice that our program prints the value we call the function with and that is just as expected and thirdly as with any other type we can also return a function from another function but more about this later on this tutorial now if we take a look at this function we wrote you notice that it returns a type of void what you need to understand is that all dart functions return a value as in our case if no return value is specified then by default the statement return null is implicitly appended at the end of the function body this can be dangerous from a null safety perspective right yes but that's why we're returning a type of void the void type actually means that the value the function is returning won't be ever used therefore if we use the dot operator on the result of this function we'll see that the dart analyzer doesn't have any suggestions for us since we can't call anything on a value of type void and now if we take a look at the first function we wrote we will be able to see that it just contains one return expression and that is return a dart comes with a very handy shorthand syntax for this case so whenever you have something like this returning a single expression you can use the arrow syntax instead just like this the return a syntax from our example just turned into this arrow syntax one thing to be noted is that only an expression can be set between the arrow and the semicolon an expression just as we learned in the previous tutorial is something that evaluates into other thing so you can't have an if statement here for example but you can use a conditional expression like this and don't worry if you don't understand this syntax we'll talk more about it in the operators tutorial coming up next in this entire course this basically means if a is odd then one else zero so you see in both cases this expression evaluates into something now before we get into discussing all kinds of parameters a function could take let's switch this discussion into another really really important topic and that is anonymous functions you see until now we're used to creating name functions since well most of the functions you'll ever play with will be indeed named however when passing a function as an argument to another function do you really need to create a separate function set it a name and then send the name as the parameter no for these specific cases anonymous functions were created you'll often hear about them as being lambdas or closures anonymous functions are functions that don't require a name all they need is the parameters list and the code block denoting the body of the function so let's take the least.map function as an example because list.map takes in a function as its parameter we'll create a list of strings and what we want to do is to uppercase every item of this list by using the map function so if we write list.map you'll see that by default dart already created the sample closure for us the map function will apply this closure for each element of type string set as a parameter and as we can see this closure will return a value of t which in our case will be the uppercased string so let's say we don't want to use anonymous functions how can we do it instead well we'd have to create a function let's name it apply uppercasechanges this function will take a string value as a parameter and return the uppercase string just like this and now since we have a name for this function we can actually pass it as an argument to the map function above if we print the list we'll see everything works pretty much fine however for little tasks like this it's not necessary to create a separate function we could use an anonymous function just like this instead so our closure will have to take in a string value and we need to mark it as a parameter the string type is optional you don't have to set it but for learning purposes i leave it on for the moment so that you'll understand that this is actually the parameters list of the anonymous function now all we need to code is the function body so we can open up the curly brackets and return the uppercase parameter we retrieved from the parameters list by calling s dot to upper case and voila you have written yourself an anonymous function since we have a single return expression inside the function body we can write it with a shorthand arrow syntax just like this therefore you can notice by yourself how big of a difference anonymous functions bring in terms of making the code more readable and easier to understand what i can recommend to you is to focus on these anonymous functions as much as possible because you'll need to deal with them many many times especially when developing flutter apps and working with the widget tree anonymous functions and parameters are some of the most crucial things to be understood without them you're simply going to get stuck at some point and your learning curve will stagnate this is actually the reason why some people don't seem to understand in flutter that this context is not the same as this one right here even though they have the same names and you'll know that it's true if you understood anonymous functions this is just a random name the name of the parameter for disclosure could be of any random name and it can only be used inside the body of this closure as we previously saw with our example it has absolutely nothing in common with the above parameter however those that haven't paid much attention to this topic will have a hard time understanding flutter and will face build context related issues later on having that said let's move over to the other really important sub topic that you need to understand about functions and that is parameters in dart you'll find four types of parameters required positional optional positional required named and optional named i'll make sure to discuss each and every type of function parameters so let's begin with the first one required positional parameters are just the standard parameters you might be used to from other programming languages they are simply enumerated between the headers round brackets they are called positional because the order in which you write them matters when you call this function somewhere in your code you need to really make sure you pass the right values to the specific parameters this is why i don't kind of like these parameters they seem really old school from back when i was practicing c language i absolutely hate having a huge list of parameters and perhaps having to go back to where i implemented the function to see the order in which i wrote them just to make sure i set the variables the correct way it's really frustrating they are called required positional parameters because all of these must be set when the function gets called otherwise you'll get an analyzer error optional positional parameters are kind of the same thing since they're also positional parameters so the order matters but this time they're optional so you don't have to set their values when calling the function or you could just set some of them and leave the rest on set you can define optional positional parameters by declaring them between square brackets just like here however a really important thing to be noted here regarding null safety is that well when executing this function these parameters need to have a default value right and if none is provided then dart will assign them a value of no this is absolutely not safe from a new safe perspective since this might be non-newable as in our case so the thing is that every time you use optional positional parameters and they're non-viewable you need to assign them with a default value just like this or you could just make them nullable so that dart can assign them to null by default moving on to one of my favorite type of parameters required and optional named parameters are literally the best thing that could ever happen to function parameters this actually solves the issue i was talking about earlier regarding positional parameters well in the case of named parameters when calling the function you'll be able to see which parameter you're setting to what value the order in which you'll declare them or set them doesn't even matter since all you have to do is to assign the parameter to the right value plain and simple how amazing is that name parameters are such a blessing to be honest and are actually the huge foundation of flutter widgets since all these fields you're seeing here in flutter are just named parameters from inside the constructor function of their specific classes so as you saw you can declare name parameters by surrounding them with curly brackets and you can assign them in the function call by using the column operator however you might notice we have this required keyword here and here you need to know that named parameters are optional by default so you can only set the ones you want you can make them to be required by using the required keyword so a lesson to be learned from this is that you can have required and optional name parameters between these curly brackets and the same no safety rules applies to the optional name parameters too they need to have a default value if they are non-nullable in perspective you can't have required positional parameters between square brackets as required positional parameters are set outside of them therefore having this said you need to learn the following parameter rule in dart a function can have any number of required positional parameters declared first and these can be followed either by any number of named parameters between curly brackets whether they're optional or required or by any number of optional positional parameters but certainly not both at the same time what i can recommend is stick to the named parameters all the way whether required or optional because they're really easy to understand and use and can highly increase the efficiency in the development workflow now that we discussed all types of parameters in detail it's time to focus on the lexical scope as we've previously talked before in dart the scope of the variable is actually determined by the curly brackets of a function we can obviously have multiple nested functions like void a void b and voice c inside the main function if we declare a top level variable then that variable is available inside any of these methods since it doesn't have a bound if we declare a variable a var inside the a function then that variable is only available inside the function scope denoted by the curly brackets so from here right to here therefore you won't for example be able to access it in the main function above if we declare a variable b var inside the b function then that variable is only available inside the scope of function b it won't be available in function a but the a bar is still accessible inside the function b since ace lexical scope incorporates b's lexical scope i hope you get the idea here it's pretty easy to understand right now i introduce this lexical scope so that i can tell you that a local variable declared in a scope will only exist within that scope therefore after the function has been perhaps called the local variable is literally gone oh and i forgot to tell you when we were talking about function parameters a function parameter is just a local variable inside the scope of that function that will get initialized with the function call that's all they're not available outside the scope of that function but what do you think is going to happen in this case when a function's result depends on a variable from another function we learned that any function is an object so it makes sense that we can have a function returning another function right so let's look at the following example we have a function called make car that will return another function right inside the scope of our make car function we actually have two variables the make parameter and the engine local variable as you can see since the closure below is in the same scope as the make car it has access to both the make and engine variables as well as its own parameter called modal therefore as we've discussed you may think that if we call this maker function and assign it to a variable then after it finishes executing the local variables inside of it namely the make and the engine will be completely gone but dart knows that this variable holds a reference to the closure containing all the previous variables so even though that function exited its execution process they still exist you'll notice that by calling the car variable that will make the closure to be called with the m5 model parameter as you can see the program successfully printed every parameter without a miss so what you need to understand about a lexical closure is that it is a function object that has access to variables from its lexical scope even when it's used outside of its original scope just as we previously saw and having this said it's time to move on to what i wanted to show you last before we end up with this tutorial if you ever created a class that you want it to be called like a function all you have to do is to implement the call method inside that class just like this whenever you'll create an instance of that class and assign it to a variable now you can literally call that class as a function by using the default parenthesis and voila you now have a callable class or even more interesting than that you can double call the a class the first call will be for the constructor and will create the a object and the second one will be for the call method how cool is that i bet you haven't seen this syntax before having that said it is finally time to end this tutorial on dart functions i hope you understood them in great detail in the next tutorial we'll move over to the next station on this dart language tour in which we'll discuss all dart operators as always if you like this tutorial don't forget to smash that like button subscribe to my channel and share the video with all of your friends and colleagues in pursuit of top tier development until next time as always take care wicked is out bye bye
Info
Channel: Flutterly
Views: 1,725
Rating: undefined out of 5
Keywords: dart, dart tutorial, dart course, dart complete course, dart functions, dart anonymous functions, dart lambdas, dart closures, dart function parameters, dart parameters type, dart positional parameter, dart named parameter, dart required, dart required keyword, dart required nullsafety, dart required named parameter, dart lexical scope, dart lexical closure, dart callable classes
Id: xL_uC8qm2L4
Channel Id: undefined
Length: 19min 30sec (1170 seconds)
Published: Thu Jul 08 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.