Swift Syntax – Why Closure Declaration Differs from Function Declaration

closuresswift-languagesyntax

let closure = { (args) -> ReturnT in ... }

v.s.

func function(args) -> ReturnT { ... }

Why didn't Apple follow principle of Occam's razor and make closure and function declarations to be equal? For example, closure could be defined like this:

let closure = (args) -> ReturnT { ... }

This is how it implemented in JavaScript and other scripting languages. This is also looks more reasonable because function and closure are actually identical. And, in contrary, putting arguments and return type inside the brackets looks weird and could mess a programmer.

Best Answer

Swift chose lambda-style syntax for their function parameters in ordinary functions as well. The only difference between an ordinary function and a closed-over one is the positioning of the braces and the use of the in keyword.

Apple describes Closures as "self-contained blocks of functionality that can be passed around and used in your code." This concept of a "block" style is evident in all of their examples.

For example, this ordinary function:

func backwards(s1: String, _ s2: String) -> Bool {
    return s1 > s2
}

Can be passed to a Sort function to reverse the sort:

var reversed = names.sort(backwards)

In closure form, you would pass a block of code to the function like this:

reversed = names.sort( { (s1: String, s2: String) -> Bool in return s1 > s2 } )

Which doesn't look like much. However, the syntax allows you to make some optimizations. Type inference allows you to shorten it to

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

Implicit Returns allow you to shorten it to

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

And Shorthand Argument Names allow you to shorten it to

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

However, the most interesting syntax variation is the "Trailing Closure," which allows you to hand the closure to the last method argument outside of the parentheses. Because the sort function only takes one argument, you can also omit the parentheses. So now it looks like this:

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

This may seem like a minor difference, but consider this example:

let strings = numbers.map {
    (number) -> String in
    var number = number
    var output = ""
    while number > 0 {
        output = digitNames[number % 10]! + output
        number /= 10
    }
    return output
}

which uses a trailing closure in a map function. The braces don't look so awkward anymore, do they?

Further Reading
The Swift Programming Language: Closures

Related Topic