Apple opened a blog to write about and promote Swift, which is really rare in Apple's history. And there is a post there, which mentioned the @autoclosure keyword.

@autoclosure is an amazing creation of Apple, it "seems" more likely a hack for this language. The thing @autoclosure does is encapsulating a statement into a closure, automatically. This slicks up your code almost all the time, turning it understandable and neat.

Consider we have a method, which accepts a closure as parameter. When the closure is evaluated as true, print a string:

func logIfTrue(predicate: () -> Bool) {
    if predicate() {
        print("True")
    }
}

And we have to write this code to call it:

logIfTrue({return 2 > 1})

It is annoying: What is that return and there are () and {} pairs which make the code difficult to understand.

Of course, we could simplify the closure in this situation. Here it would be no problem to omit return, making the code above to:

logIfTrue({2 > 1})

One step further, there is a syntax called trailing closure. We can omit the parentheses as well:

logIfTrue{2 > 1}

Fairly well, but not enough. If a programmer just switches to Swift and has no idea about trailing closure, he may be confused with the brace. Now, if we use @autoclosure, we can make the world better for everyone. Just adding @autoclosure in front of the parameter type:

func logIfTrue(@autoclosure predicate: () -> Bool) {
    if predicate() {
        print("True")
    }
}

Now, we can write this:

logIfTrue(2 > 1)

to call the logIfTrue method. Swift will transform the statement 2 > 1 into a () -> Bool closure behind the scene. So we can have a good and simple expression.

Another important use case is ?? operator. ?? can be used in nil condition check. If the left-hand of this operator is a non-nil Optional, the unwrapped value would be returned, otherwise, the right-hand default value will be used. Just a simple example:

var level : Int?
var startLevel = 1

var currentLevel = level ?? startLevel

Here we do not set level when we declare it, so it will be a nil. In the currentLevel statement, startLevel is assigned to currentLevel, since there is no value in level. If you are a curious cat, you may already click into the definition of ??, which contains two versions:

func ??<T>(optional: T?, @autoclosure defaultValue: () -> T?) -> T?
func ??<T>(optional: T?, @autoclosure defaultValue: () -> T) -> T

In the example, we are using the latter one. Although it seems we are passing startLevel as a simple Int, it is a () -> Int in fact, and is wrapped automatically by the @autoclosure feature. Think about how ugly it will be if there is no @autoclosure! With the hint of this method signature, we can try to implement this operator ourselves, like this:

func ??<T>(optional: T?, @autoclosure defaultValue: () -> T) -> T {
    switch optional {
        case .Some(let value):
            return value
        case .None:
            return defaultValue()
        }
}

Think deeper, and you may have a question about this operator: Why does not this operator just accept a T as right-hand parameter? Is it not simpler by just using T instead of @autoclosure? That is the greatest part of @autoclosure. If we use T, that means we need to prepare everything ready, both the left and right-hand parameters, before passing them to the ?? operator. However, once the left-hand value optional is not nil, the unwrapped value will be returned immediately. In most case, it will not be a problem, but consider the situation that we are using a very complex algorithm to calculate the defaultValue. We have to prepare it every time using ?? operator, but in fact there is a possibility that we will not use it at all. What a waste! This could be avoided in fact. The key is delaying the calculating for defaultValue, making it follow the nil check. The answer is @autoclosure it, so it will not be executed until optional falls into the .None case.

With @autoclosure, we are not only bypassed the conditional checking and explicitly conversion, but also get a benefit in performance. But there is also limitation when using @autoclosure. It cannot support method with parameter, in other words, you cannot mark @autoclosure except for () -> T. Another trap is the caller of your code might not notice you want to accept an autoclosure parameter. When writing methods with @autoclosure, it is better to keep it simple and clear. If the parameter might create an ambiguity or be difficult to understand, please make the choice of turning to a complete closure, so everyone could know what happens in the code.

Exercise

In Swift, the logical operator && and || are using @autoclosure as well. Now, why not open your Playground and try to implement them yourself? I think you can master this feature by doing so.