How to use Swift @autoclosure

Joel Fischer picture Joel Fischer · Jun 8, 2014 · Viewed 29.9k times · Source

I noticed when writing an assert in Swift that the first value is typed as

@autoclosure() -> Bool

with an overloaded method to return a generic T value, to test existence via the LogicValue protocol.

However sticking strictly to the question at hand. It appears to want an @autoclosure that returns a Bool.

Writing an actual closure that takes no parameters and returns a Bool does not work, it wants me to call the closure to make it compile, like so:

assert({() -> Bool in return false}(), "No user has been set", file: __FILE__, line: __LINE__)

However simply passing a Bool works:

assert(false, "No user has been set", file: __FILE__, line: __LINE__)

So what is going on? What is @autoclosure?

Edit: @auto_closure was renamed @autoclosure

Answer

eddie_c picture eddie_c · Jun 8, 2014

Consider a function that takes one argument, a simple closure that takes no argument:

func f(pred: () -> Bool) {
    if pred() {
        print("It's true")
    }
}

To call this function, we have to pass in a closure

f(pred: {2 > 1})
// "It's true"

If we omit the braces, we are passing in an expression and that's an error:

f(pred: 2 > 1)
// error: '>' produces 'Bool', not the expected contextual result type '() -> Bool'

@autoclosure creates an automatic closure around the expression. So when the caller writes an expression like 2 > 1, it's automatically wrapped into a closure to become {2 > 1} before it is passed to f. So if we apply this to the function f:

func f(pred: @autoclosure () -> Bool) {
    if pred() {
        print("It's true")
    }
}

f(pred: 2 > 1)
// It's true

So it works with just an expression without the need to wrap it in a closure.