Background:
@autoclosure is a special Swift modifier that allows for the automatic creation of a closure from an expression passed as a function argument. It first appeared to simplify syntax and improve readability when writing assert/guard expressions and deferred value computations.
Problem:
Standard closures require explicit syntax ({ ... }). This is often redundant when the logic is simple (for example, in lazy checks). However, using autoclosure can subtly change the execution timing of the code or lose the side-effect value of the expression, unnoticed by the developer. Moreover, autoclosure does not take parameters.
Solution:
@autoclosure allows for concise writing:
Code example:
func logIfTrue(_ predicate: @autoclosure () -> Bool) { if predicate() { print("Condition met") } } // Without autoclosure: logIfTrue({ 2 > 1 }) // With autoclosure: logIfTrue(2 > 1)
Key features:
Can autoclosure take parameters?
No. Autoclosure is always context-free: it takes 0 parameters and simply "wraps" the expression.
What is the difference between types () -> T and @autoclosure () -> T?
A regular closure requires explicit syntax — autoclosure allows passing an expression without surrounding it with curly braces, which significantly impacts function interfaces.
What happens if autoclosure has a side-effect?
The autoclosure is computed only when called — if the expression performs a side effect, it will occur strictly at the time of the call, not when passing the parameter to the function.
var x = 5 func change(_ value: @autoclosure () -> Int) { print(value()) } change(x += 1) // x will only increase HERE
In implementing error analytics, messages were written using a function that employed autoclosure for reporting. However, the message expression had a side effect (it sent a network request), so the actual execution happened out of the expected order for the developer. Consequently, the statistics were collected incorrectly.
Pros:
Cons:
Using autoclosure in assert methods, where it is either required to compute an expression only when necessary, or to simplify the syntax for the API end-user. The code becomes shorter, with no side effect.
Pros:
Cons: