7 days of WordPress plugins, themes & templates - for free! Unlimited asset downloads! Start 7-Day Free Trial
FREELessons: 30Length: 4.8 hours

Next lesson playing in 5 seconds

  • Overview
  • Transcript

5.4 Closures

Building on the concept of function types is that of closures. Closures in Swift are similar to what you might have encountered in other languages under the name of lambdas, or lambda expressions. These constructs allow full functions to be created inline with a much more compact syntax.

5.4 Closures

The final piece of the puzzle that I would like to discuss with you regarding functions and Swift. Has to do with a similar thing that we talked to previously when we started to talk about function types. Now in this lesson, we're gonna talk about something called closures. And sometimes in other languages you may have heard of this topic closure referred to as a lambda or a lambda expression. But ultimately, it's the same thing. Whereas a closure or a lambda expression is really just encapsulating the functionality of a particular function. And getting rid of all the extra stuff the name of the function and sometimes some of the types of the input parameters and output parameters and stuff like that. And just being able to figure it out with this kind of floating body of a function. And this can kind of take you into some of the areas known as functional programming, which we'll leave for another course. But in this case, it's going to be somewhat similar. So let's revisit an example we had previously. Let's say I had a function and it was called my function. And maybe it took in a name that was of type string, and it returned a string. So we saw this previously, and we could just return some value. It's really not necessary to put anything in there at the moment. And we could define another function. In this case, we'll just call this input function, or you can call it whatever you like, and it's gonna take in a function f. That's going to have a function type or a signature of an input value of a string and an output value of a string. And maybe it's gonna take in another value called input, which is going to be of type string. So what we can do at this point now is we can call this input function F, which takes in a string. And we could pass in input to this particular function. And we could go on our merry way. And everything would be just fine. Now this is acceptable code because this is kind of part of the way that the language was designed. We can absolutely do this. But you're not gonna see this very often out in the wild because it's a little bit extra code. So what do I mean by extra code? Well, the signature of input function if you were to take a look at it, is going to be defined by the fact that it takes in a function and some sort of input. Now, in order for us to actually do something with this function. We're actually going to have to define a function that has that particular function type in order to pass it into here. And while that is absolutely valid it's a little bit wordy and a little bit extra work. So what if we could trim that down a little bit to make it a little bit easier to work with. So let's create a very simple example here that might make a little bit more sense and that's actually built in to the world of Swift. So one thing that we have here in Swift is this concept of an array which we worked with before. So I could say var names is going to be equal to and we'll just give this a few names. We'll say Derek, Anna and Shawn. So now let's say we had this array of names and ultimately I wanted to sort these. I wanted to sort these in some way. Well there's a function that's built in to the array called sort. Now there's a couple different ways that you can do this, but the one of interest is the second one here that has is ordered before. And it takes in a function type. So I have two elements that are going to get passed in here. So this is a generic. But just imagine in our case that these elements are actually strings. And it's going to return a boolean. So effectively what's going to happen here is we're going to pass in some sort of function type, or what I'm going to show you the moment, a closure. That is ultimately going to determine if it were to compare two values together that were strings in our case, if the first parameter comes before the second parameter. And then that's going to be how this particular sort function works to ultimately reorder these values. So yes, I could absolutely create a function that would take in a couple of different values, in our case two strings. And then it would return whether one was less than or the other, less than the other. So I could say function order. Which is going to take in first, which is going to be string. And second, which is going to be a string. And then is ultimately going to return a boolean. And at this point all I'm really going to do is I'm going to return whether or not first is less than second. So this is going to be a valid function. So then what I could do at this point is I could say, var sorted is gonna be equal to names.sort. And then I could pass in my function order to actually handle the sorting the actual internal logic of the sorting. And then it would actually sort my array. Now, you can absolutely do this, but you're more than likely not going to see this out in the wild. What you're going to see is the use of a closure in place of this function type. So, how do we do that? So let's just start by actually replacing the actual function type that we're passing into the sort by a closure. So let's create our closure. Now, a closure is defined by the open and closed curly brackets. So now this is going to tell the sort function and ultimately the swift compiler that we're gonna pass in a closure that's going to represent a specific function type. And that function type if you recall is going to be just what we created up above here. So let's duplicate this function type into our closure. We have open and close parentheses. Because we have two values that are the inputs. We have first, which is going to be a string. And we also have second, which is going to be a string. So I've just take in the input parameters here and copied them down into our closure. Now I'm also going to add our return type which is going to be a Boolean. And now I need to specify the body, how do we specify the body? Well in a closure instead of using curly brackets what we do is we specify our in keyword and the in is going to specify that everything that comes after this is going to be. A statement that's going to be the body of our closure or the actual functionality. So in our case all we want to do is we want to return first So there we have successfully replaced the passing in of a function type into our sort function with a closure. Now this may seem a little bit wordy and maybe it doesn't seem like we've saved very much from passing this into the sort function as we did from here, but we can optimize this a little bit more. So what we can start to do here is we can start to infer some of the typing of our parameters, our input parameters as well as our return value, based on the signature of sorts. However, look in here again. You're going to see that I'm taking in a function that has two input values of a generic type element and it returns a boolean. And because it's defined that way Swift in the compiler know that these parameters have types. And that they're going to be handled within our function within our closure body correctly. So we don't have to specify the types anymore as this stuff can be inferred. So I don't need the return value either. So we've gotten rid of some of that extra stuff in there that we don't necessarily need, that the compiler will be able to fill in for us. Now the other nice thing that we can do here, and not necessarily in all closures but within closures that only contain a single expression, which in ours it does. We have first less than second, that's the only value we have. We can actually get rid of the return keyword as well. Because Swift and the compiler are going to assume that we're going to return the value that is the result of whatever operation or whatever expression is that we're using here. Now that's pretty nice. We're really starting to really compact this down to make this a little bit more functional, if you will. But we can take it even farther. So one of the other nice things that we can do with enclosures is we can start to use what are known as shorthand arguments. Now shorthand arguments are really just us specifying positional arguments within our closure. And we do that by using a special notation, and that's using the dollar sign, and then the number of the argument that's being passed in. So really at the end of the day that means we're replacing our input parameters with dollar sign zero, and $1. And these are our positional arguments. So I can do $0 on both sides and $1. But because we're able to do this now. We can actually take it a step farther and we can actually get rid of the input parameters as positional is here as well as in and those can actually be inferred by what it is we're doing here. So what we've basically done here is we've gone from having to create a fully implemented function with input parameters with an output parameter, with a function body. And then ultimately creating a variable that could point to that particular function, and then passing that into our sort function. We've actually got rid of all of this extra code and we've broken it down to a simple closure or a lambda expression. Now this is very useful in a lot of places throughout swift and a lot of the libraries that you're going to be interacting with because you're going to see. That you are able to pass inputs into a number of functions. These function types are ultimately closures. So at that point, you have a choice. You can either create these functions, these fully implemented functions, and then pass them into your function as an argument, like we saw in the previous lesson. Or you can replace that with an in place closure. So it's really up to you whatever you're more comfortable with. If you're looking to be very explicit about what's going on and very verbose, then that's absolutely fine. I can understand that. Then you'll want to create a fully implemented function and go ahead and pass it in to whatever the input of another function is. But if you want to cut down on code as much as possible, then maybe closures are the way to go. Because there's a lot of optimizations you can do as you're going in and creating those. So closures can be very helpful in both ways.

Back to the top