Closures in Swift

Closures

A Closure is a self-contained block of functionality that can be passed around and used in your code.

Global and nested functions are actually special kinds of closures.

Nested functions offer a convenient way to name and define self-contained blocks of code within a larger function.
However, it is sometimes useful to have the option of writing shorter versions of function-like constructs that do not require full declarations and names. This is particularly true when working with functions that take other functions as one or more of their arguments.

Closure expressions present a way to write inline closures using brief, focused syntax. Closure expressions offer a number of syntax optimizations for use in writing closures in a shortened form, without losing clarity or intent.

Closure expression syntax takes the following general form:

{ (parameters) -> return type in
 statements
}

Closure expression syntax can use constant parameters, variable parameters, and inout parameters, but default values cannot be used. Variadic parameters can be used if you name them and make sure that it’s placed last in the parameter list.

The Sort Function

To understand how Closures are used, let’s take a look at a function called sort, which is available in Swift’s standard library. The sort function orders an array of values of a known type.

The sort method takes two arguments:
– An array of values of a known type.
– A closure that takes two arguments of the same type as the array’s contents, and returns a Bool value to say whether the first value should appear before or after the second value once the sorting is complete.

The example below shows the sorting of an array of String values. The sorting closure needs to be a function of type (String, String) -> Bool.
One way to provide the sorting closure is to write a normal function of the correct type, and to pass it in as the sort method‘s parameter:

func backwards(s1: String, s2: String) -> Bool {
   return s1 > s2
}
let names = ["Cc", "Aa", "Ee", "Bb", "Dd"]
var reversed = names.sort(backwards)

The example compares the Strings in the array names, based on the backwards function.
However, this is a long-winded way to write what is really a function that contains a single-expression (a > b).
In this situation, it would be preferable to write the sorting closure inline, using closure expression syntax:

let names = ["Cc", "Aa", "Ee", "Bb", "Dd"]
reversed = names.sort({ (s1: String, s2: String) -> Bool in
   return s1 > s2
})

For the inline closure expression, the parameters and return type are written within the curly braces, rather than outside of them.
The in keyword is used to introduce the beginning of the closure’s body, and indicates that the definition of the closure’s parameters and return type has finished, and the body of the closure is about to begin.

Inferring Type from Context

The sorting closure is passed as an argument to a function, making it possible for Swift to infer the types of its parameters and the type of the return value from the type of the sort method‘s second parameter. This parameter expects a function of type (String, String) -> Bool. This means that writing the (String, String) and Bool types as part of the closure expression’s definition is not necessary. Because all of the types can be inferred, the return arrow (->) and the parentheses around the names of the parameters can also be omitted:

reversed = names.sort( { s1, s2 in return s1 > s2 } )

The parameter types and return type can always be inferred when passing a closure to a function as an inline closure expression. As a result, it is unnecessary to write an inline closure in its fullest form when the closure is used as a function argument.
You still have the option of writing out the types. In fact, doing so is encouraged when you need to avoid ambiguity for others who might read your code.

Single-expression closures can implicitly return the result of their single expression, simply by omitting the return keyword from the declaration, as in this new version of the previous example:
reversed = names.sort( { s1, s2 in s1 > s2 } )

Here, the function type of the sort method‘s second argument makes it clear that a Bool value must be returned by the closure.
Because the closure’s body contains a single expression (s1 > s2) that returns a Bool value, there is no ambiguity, and the return keyword can be omitted.

Shorthand Argument Names

Swift automatically provides shorthand argument names for inline closures. These argument names can be used to refer to the values of the closure’s arguments, with the names $0, $1, $2, and so on.

If you use these shorthand argument names within your closure expression, you can omit the closure’s argument list from its definition, and the number and type of the shorthand argument names will be inferred from the expected function type. The in keyword can also be omitted, since the closure expression is entirely made up of its body:

reversed = names.sort( { $0 > $1 } )

Here, $0 and $1 refer to the closure’s first and second String arguments.

Operator Functions

There’s actually an even shorter way to write the closure expression above. Swift’s String type defines its string-specific implementation of the greater-than operator (>) as a function that has two parameters of type String, and returns a value of type Bool. This exactly matches the function type needed for the sort method‘s second parameter. Just pass in the greater-than operator, and Swift will then infer that you want to use its string-specific implementation:

reversed = names.sort(>)
Advertisements
Closures in Swift

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s