Intro to Closure Expression Syntax in Swift

If Swift is your first programming language, understanding closure expressions can be tough. It’s a broad topic, and unlike classes or functions, the syntax can take some getting used to, largely because there’s so much shorthand.

This post focuses on understanding syntax and shorthand as a way to get a foothold.

Getting Started

Closure expressions are similar to functions, but unlike functions, they don’t need a name. We’re going to play with a closure inspired by We Heart Swift’s basic example. I strongly suggest opening up a playground and experimenting as you read.

var morningGreet: () -> (String) = {
return "Good morning!"
}
// returns "Good morning!"
morningGreet()

This should look similar to a computed property that you might see in a class declaration, except morningGreet has a type of () -> (String), which means it takes no parameters and returns a String.

Full Closure Expression Syntax

Let’s modify morningGreet so that it takes in a String parameter:

var morningGreet: (String) -> (String) = { (name) -> String in
return "Good morning, \(name)"
}
// returns "Good morning, Ben!"
morningGreet("Ben")

What’s going on here? This example shows the three elements of closure expression syntax: parameters, return type, and statements.

So what is (name)? (name) refers to the instance of our first parameter that will get used later in the closure’s body. We could rename name banana, oyster or asldfjhad, and as long as we referenced that new name in our body, morningGreet would work just the same. This is somewhat similar to a for in loop, where you use shorthand to create a variable for each item in an collection (i.e., for apple in appleBasket {//do something with each apple}).

Although it is redundant, we explicitly reference our return type, String, after our parameter, (name) .

What is in? in functions as a divider between our expression’s return type and body where we write our statements. It is similar to {} in a standard function.

In our body, return “Good morning \(name)" is similar to what we had before, but it now incorporates our newly defined parameter.

If that’s making sense (and if it’s not, keep playing around in your playground), let’s make this shorter by inferring types.

Make it Shorter

Let’s take out the closure’s type declaration that we had written right after morningGreet. We can do this because Swift can infer it from our parameter, (name: String).

var morningGreet = { (name: String) -> String in
return "Good morning, \(name)"
}

In the next example, we get rid of the return type. This is because Swift can infer it from our closure’s body statement: return "Good morning, \(name)" .

var morningGreet = { (name: String) in
return "Good morning, \(name)"
}

In the third example, we lose the word return all together and put everything on one line. Swift is smart.

var morningGreet = { (name: String) in "Good morning, \(name)"}
// still returns "Good morning, Ben!"
morningGreet("Ben")

Let’s use Swift’s shorthand for arguments: $0, $1, $2, and so on. Now we need to put the type declaration back in, since our shorthanded argument name leaves nothing for Swift to infer from.

var morningGreet: (String) -> String = {
return "Good morning, \($0)"
}

Remember that good old first morningGreet ? Well, we could write it like this, which should make a lot of sense now:

var morningGreet: () -> (String) = { (Void) -> String in
return "Good morning!"
}

There’s more, but let’s stop here for now.

Beyond

Closures have a lot of power — trailing closure syntax, the ability to capture values, get really short with operator methods, etc.. They are often used when you want something to happen after something else, like a server call that takes time to return something.

Hopefully this has a been a useful primer in understanding the foundations of closures in your code :)

Show your support

Clapping shows how much you appreciated Ben Bernstein’s story.