Figure

A blog about Swift and iOS development.

Functions are Just Named Closures

We know Swift was designed with closures in mind and that they're integrated deeply into the language (as opposed to being bolted on after the fact a la ObjC blocks). In fact, as the Swift documentation points out

Global and nested functions … are actually special cases of closures.

That's right. The closure is, in fact, the basic building-block of functions and methods in Swift. How far can we take this? Let's look at a clunky Cocoa API that looks even clunkier in Swift:

UIView.animateWithDuration(0.3, animations:{
  myView.frame = animatedFrame()
  myView.alpha = animatedAlpha()
}, completion:{ finished in
  resetParameters()
  cleanUpIntersitialViews()
})

Ugh. When we have two closure params in Swift, even trailing closure syntax won't save us. One way to clean up this mess is to assign our closures to constants, and pass those into the animation method:

let animations = {
  myView.frame = animatedFrame()
  myView.alpha = animatedAlpha()
}

let completion = { finished in
  resetParameters()
  cleanUpIntersitialViews()
}

UIView.animateWithDuration(0.3, animations: animations, completion: completion)

Which is great, as far as it goes. But all we're really doing here is assigning our closures a name so that we can refer to them later. Swift already has a way to do that: functions!

func animations(){
  myView.frame = animatedFrame()
  myView.alpha = animatedAlpha()
}

func completion(finished:Bool){
  resetParameters()
  cleanUpIntersitialViews()
}

UIView.animateWithDuration(0.3, animations: animations, completion: completion)

Yes, a function is essentially just a closure that's been assigned to a constant. There's no real difference between func foo(){…} and let foo = {…} as far as Swift is concerned, and that means we can pass function names as parameters to methods that expect closures.

But what has this accomplished? True, it's really just a semantic change, and a lateral one at that (though, to my eyes, this is easier to read because I'm more used to parsing functions than I am closures). But how often have we found ourselves writing closures that do nothing more than call a single function?

[firstName, lastName].map{ processField($0) }
NSBlockOperation{ doBackgroundThing() }

Now that we know we can pass around functions in the place of closures, we can simplify these statements:

[firstName, lastName].map(processField)
NSBlockOperation(block: doBackgroundThing)

But more importantly, understanding the interchangability of functions and closures (and how the former is, in fact, implemented in terms of the latter) gives us a better framework with which to understand both.


Hit me up on twitter (@jemmons) to continue the conversation.