Programming in Swift: Functions & Types

Jan 4 2022 · Swift 5.5, iOS 15, Xcode 13

Part 2: Closures

10. Closures

Episode complete

Play next episode

Next
About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 09. Introduction Next episode: 11. Challenge: Closures

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Notes: 10. Closures

Update Notes: This course was originally recorded in 2019. It has been reviewed and all content and materials updated as of October 2021.

Transcript: 10. Closures

As I said, closures and functions are really just different flavors of the same thing. Actually, technically, functions are a special type of closure!

But, usually, when you hear someone talking about closures, they’re talking about closure expressions. That’s where some important differences come in. The one you’ll hear most often is that closures don’t have names like functions do.

But closures also have their own syntax and small differences in capabilities. Grab the playground for this part of the course, and we’ll get started using closures based on what you already know about functions.

Let’s start by revisiting some code from the last episode on functions. Remember this add function? Let’s assign that function to a variable, again.

var operate = add

Then call add and pass in any two numbers you like…

add(number1: 7, number2: 3)

and call operate with the same two numbers:

operate(7, 3)

We get the same result in the sidebar, as expected, but these two function calls look different. operate doesn’t have argument labels. That’s because when you store a function in a variable, like operate, that variable is really a closure!

You can create a closure directly, as well. Closures have their own syntax, but it is similar to function syntax.

Let’s recreate the add function in closure-form, as an example. Right below operate, make a new variable and call it addClosure.

var addClosure

You can explicitly type closures just like any other value! Closure types are exactly the same as function types, so you could define the type in the closure declaration with a parameter list and return type.

Our add closure will take two Ints and return an Int, so the type looks like this:

var addClosure😺: (Int, Int) -> Int

But I also included our Operate typealias in this playground page, so we can use that instead.

var addClosure: 😺Operate

To assign a value to the closure, use the assignment operator just like you would when declaring an Int or a String. Then follow it up with a pair of curly braces.

var addClosure: Operate 😺= {

}

Closures have most of the same basic ingredients as functions. They don’t have names, but they do have parameter lists, return types, and bodies.

But with closures, all of those things go inside of the curly braces. So this closure will take two Ints in its parameter list…

var addClosure: Operate = { 😺(a: Int, b: Int)

and it will return an Int…

var addClosure: Operate = { (a: Int, b: Int) 😺-> Int

To start the body of the function, use the keyword in, instead of a curly brace

var addClosure: Operate = { (a: Int, b: Int) -> Int 😺in

You can use the return keyword before the value you want to return. In our case, we’re just adding the two parameters together.

return a + b

But just like functions, if there is only one statement in the body, a closure will implicitly return the result of that statement. So we can just delete the return keyword!

❌return❌ a + b

Like other types, closures can use type inference! So if you’re assigning a value right away, like we are with addClosure, you don’t need the explicit typing.

var addClosure❌: Operate❌ = 

Now, you can call addClosure similar to how you would call a function.

addClosure(7, 3)

Once again, we’re missing the argument labels. That’s because closures don’t have argument labels! The parameter names are only used inside of the closure body, and you can’t add different argument labels like you can with functions.

var addClosure = { (😺num1 a: Int, 😺num2 b: Int) -> Int in

Closures also don’t let you provide default values for parameters.

var addClosure = { (a: Int, b: Int😺 = 10🛑) -> Int in

Now, I’ve also copied our higher-order function, printResult, to this playground. As I’ve said, we can pass any thing that matches the type signature of Operate into this function! Anything that takes two Ints and returns and Int. So we can use the add function…

printResult(add, 4, 5)

Or the operate variable

printResult(operate, 4, 5)

or the addClosure variable

printResult(addClosure, 4, 5)

or the plus operator!

printResult(+, 4, 5)

And all of those will work! As a general rule, though, if a function or operator that does what you need already exists, use that instead of writing your own.

So, in this case, you would really just want to use the plus operator in this printResult function. Something you can do with closures that you can’t do with a function is define one inline as an argument.

Let’s write an inline closure that couldn’t be easily replaced by an existing function or operator. It can multiply two Ints together and add 100. Start with the function call and let it autocomplete…

printResult(operate: (Int, Int) -> Int, a: Int, b: Int)

Then, in place of that first argument, open up a set of curly braces…

printResult(
  { 

  }...

Now we can follow the same pattern as in addClosure. Start with the parameter list…

  (a: Int, b: Int)

then the return token and return type…

  (a: Int, b: Int) 😺-> Int

And the in keyword to say we’re starting the body of the closure now

  (a: Int, b: Int) -> Int 😺in

Then wrap it up by multiplying the two parameters together.

    a * b  + 100

And because that’s just one statement, the result will be returned for us without the return keyword. Now just fill in the other two parameters with some ints…

    a * b + 100
  }, 
  3, 10
)

And run the playground to make sure it works…

There you go! Inline closures like this are a great alternative to functions you would only use one time.

To review, here are some of the key differences we saw between closures and functions:

Functions have names, but closures do not. Functions can have argument labels and default values. Closures don’t have either of those things.

Closures can be used inline, right in a function call. You can’t do that with functions.

Closures have different syntax! Their parameter list and return type go inside of the curly braces, and the closure body is denoted by the keyword in.

Closures also have a lot of options to shorten the syntax, which can make their inline usage even nicer. But before we get into that, I’ve got a challenge to help you practice what you’ve learned already.