A Basic Tutorial on Functions and Closures in Swift

Note: this is an article for people new to functional programming style, and to closures. Unlike the rest of this blog, it is very much an explantion for beginners, so if you’re already familiar with these topics you might want to skip it.1 You may find these other articles interesting though – Implemeting an Accumulator in Swift, and A Straw-man Argument for Trying More Functional Programming in Swift.

If you like this post, consider buying a copy of our book, Advanced Swift, which includes introductory material like this, and then builds on it to cover many more advanced Swift topics.

Reading the /r/swift subreddit and stack overflow, there seems to be a lot of questions about functions and closures from programmers learning Swift. There’s confusion between what a closure is, what a function is, and what a closure expression is. And many people are new to the whole idea of functions being first class objects. This article is an attempt to help out.

To understand functions and closures in Swift you really need to understand three things, in roughly this order of importance:

  1. Functions can be assigned to variables and passed in and out of other functions as arguments, just as an Int or a String can be.
  2. Functions can “capture” variables that exist outside of their local scope.
  3. There are two ways of creating functions: with the func keyword, or with { }. Swift calls the latter “closure expressions”.

I suspect people new to the topic of closures are coming at it in reverse order, and maybe missing one of these points, or conflating the terms “closure” and “closure expression”, and that this can cause a lot of confusion. It’s a three-legged stool, and if you miss one of the three points above, you’ll fall over when you try to sit down.

1. Functions can be assigned to variables and passed in and out of other functions as arguments, just as an Int or a String can be.

In Swift, as in many modern languages, functions are referred to as “first-class objects”. You can assign functions to variables, and you can pass them in and out of other functions, to be called later.

This is the most important thing to understand. “Getting” this for functional programming is akin to “getting” pointers in C. If you don’t quite grasp this part, everything else will just be noise.

Here is an example of assigning functions to variables and passing them to functions:

// This is a function that takes an Int and prints it. 
func printInt(i: Int) {
    println("you passed \(i)")

// This assigns the function you just declared
// to a variable.  Note the absence of () after the 
// function name.
let funVar = printInt

// Now you can call that function using your variable. 
// Note the use of () after the variable name.
funVar(2)  // will print out "you passed 2" 

// You can also write a function that takes a
// function as an argument
func useFunction(funParam: (Int) -> () ) {
    // call the passed-in function:

// You can call this new function passing in either 
// the original function:
// or the variable

Why is being able to treat functions like this such a big deal? Because it allows you to easily write “higher-order” functions, which take functions as arguments and apply them in useful ways.

For example, arrays have a member function map that takes a function and applies it to each member of the array, returning a new array containing the results.

// a simple function that doubles an int
func doubler(i: Int) -> Int { return i * 2 }

// the following runs doubler on each number,
// returning a new array of the results
let a = [1, 2, 3, 4].map(doubler)

// a now contains [2, 4, 6, 8]

There are several other member functions in array that take functions – filter (takes a function that examines each element for inclusion in the returned array), sort (takes a function that determines a custom ordering for two elements), reduce (takes a function to incorporate each element in turn into a running value – e.g. plus to sum them, max to find the highest value element).

2. Functions can “capture” variables that exist in the context they were declared

You can also return functions from other functions:

// This is a function that returns another function.
// That other function takes an Int and returns nothing.
func returnFunc() -> (Int) -> () {
  func innerFunc(i: Int) {
    println("you passed \(i) to the returned func")
  return innerFunc

let f = returnFunc()
f(3)  // will print "you passed 3 to the returned func"

(The funcName() ->(Int) ->() syntax can be a little confusing at first. Try not to get too hung up on it for now, come back to it in detail later when you understand more.)

If, when you declare a function, it references variables outside the function’s scope, those variables are “captured”, and stick around after they would otherwise fall out of scope and be destroyed.

To see this, let’s revisit our returnFunc function, but add a counter that increases each time we call it:

func returnFunc() -> (Int) -> () {
  var counter = 0  // local variable declaration
  func innerFunc(i: Int) {
    counter += i   // counter is "captured"
    println("running total is now \(counter)")
  return innerFunc
  // normally counter, being a local variable, would  
  // go out of scope here and be destroyed. but instead, 
  // it will be kept alive for use by innerFunc

let f = returnFunc()
f(3)  // will print "running total is now 3"
f(4)  // will print "running total is now 7"

// if we call returnFunc() again, a fresh counter
// variable will be created and captured
let g = returnFunc()
g(2)  // will print "running total is now 2"
g(2)  // will print "running total is now 4"

// this does not effect our first function, which
// still has it's own captured version of counter
f(2)  // will print "running total is now 9"

Think of these functions combined with their captured variables as similar to instances of classes with a method (the function) and some member variables (the captured variables).

A combination of a function and an environment of captured variables is called a “closure” in computer programming terminology. So f and g above are examples of closures, because they capture and use a non-local variable (counter) that was declared outside them.

3. The { } syntax for closure expressions

In Swift, you can declare functions in two ways. One is with the func keyword demonstrated above. The other way is to use a “closure expression”.

Here is the doubler function from above, written using the closure expression syntax:

let doubler = { (i: Int) -> Int in return i*2 }
// doubler can be used just the same way as before
[1, 2, 3].map(doubler)  

Functions declared as a closure expression can be thought of as function “literals”, in the same way as 1 and "hello" are Int and String literals. They are also anonymous – they aren’t named, unlike with the func keyword. The only way they can be used is if you assign them to a variable when they are created, as we do here with doubler.

The doubler declared using the closure expression, and the one declared earlier using the func keyword, are completely equivalent. They even exist in the same “namespace”, unlike in some languages i.e. if you declared doubler using func, and then doubler using let or var in the same scope, you’ll get an error that you are redeclaring something that has already been used (similar to if you tried to declare a variable with the same name twice).

Why is the { } syntax useful then? Why not just use func every time? Well, it can be a lot more compact, especially when writing quick functions to pass into other functions such as map. Here is our doubler map example written in a much shorter form:

[1, 2, 3].map { $0 * 2 }

This looks very different, because we’ve leveraged several features of Swift to compress it down. Here they are one by one:

  1. If you are passing the closure in as an argument, and that’s all you need it for, there’s no need to store it in a local variable first. Think of this like passing in a numeric expression, such as 5*i, to a function that takes an Int as a parameter.
  2. If all the types can be “inferred” from the context by the compiler, you don’t need to specify them. In this case, the function passed to map is taking in an Int (that’s what’s in the array), and returning an Int (because an Int times an Int is an Int), so we can leave the types off.
  3. If the closure expression is a single expression, you can leave off the return and it will automatically return the value of the expression.
  4. Swift automatically provides shorthand names for the arguments to the function – $0 for the first, $1 for the second etc.
  5. If the last argument to a function is a closure expression, you can move the expression outside the parenthesis of the function call. This is nice if you have a multi-line closure expression, as it more resembles a regular function definition, or other block statement such as if(expr) { }.
  6. Finally, if a function has no arguments other than a closure expression, you can leave off the parenthesis after the function name altogether.

Using each of the above rules, we can boil down the expression to the form above:

  1. [1, 2, 3].map( { (i: Int) ->Int in return i * 2 } )
  2. [1, 2, 3].map( { i in return i * 2 } )
  3. [1, 2, 3].map( { i in i * 2 } )
  4. [1, 2, 3].map( { $0 * 2 } )
  5. [1, 2, 3].map() { $0 * 2 }
  6. [1, 2, 3].map { $0 * 2 }

If you’re new to functional programming in general, and to Swift syntax, then these compact function declarations might seem daunting at first. But as you get more comfortable with the syntax, and with using functional programming style, they will start to feel more natural and you’ll be grateful for the ability to remove the clutter so you can see more clearly just what the code is doing. Once you get used to reading code written like this, it’ll be much clearer to you at a glance than code doing the same thing in a conventional for loop.

One final point on naming. It’s important to remember that functions declared with func can be closures, just like ones declared with { }. Remember, a closure is a function combined with any captured variables. While functinos created with { } are called “closure expressions”, people often refer to this syntax as just “closures”. But don’t get confused and think that functions declared with the closure expression syntax are different from other functions – they aren’t.2 They are both functions, and they can both be closures.

Once you think you understand everything in this article, try reading some more advanced articles that involve closures on this blog – Implemeting an Accumulator in Swift, and Implementing Ruby’s ||= in Swift.

  1. Or read it for the purpose of giving me nitpicking feedback, which would be great. 
  2. Well, OK, they are. For example you can’t do the skipping the return statement trick with a one-line func. But that’s just syntactic sugar, the point is they don’t differ in the fundamental way they behave.