Fernando Olivares

August 8, 2023

What is the difference between an autoclosure and a closure that is evaluated depending on conditions?

While learning SwiftUI using the excellent "Thinking in SwiftUI" book by obc.io authors, I ran into this example (emphasis mine):

1. The counter view is created, but the value of the state object isn't present yet, because the initial value is stored as an autoclosure.

I kept on reading but I got the annoying feeling that I shouldn't. I've heard about autoclosures before but I don't think I understand them. This is a clear sign that I should stop reading and try and understand what an autoclosure is.

During my search, I found several examples that are more or less like this example from Swift by Sundell:

The explanation in Sundell's site (along with a few others I'll link to at the bottom) is that autoclosures serve two different purposes:

  • ✅ Autoclosures offer syntactic sugar so that you can create functions that accept expressions, which are then wrapped in a closure. The function may then choose to use the closure.
  • ❓ By wrapping the function parameter in a closure, autoclosures offer delayed execution of that function.

The first point I understand completely. It's very easy to see. If I rewrite that same example, using a nonautoclosure closure, we lose the syntactic sugar.


However, the second point is puzzling. Autoclosures offer delayed execution? I don't completely understand that. If we go back to the first example:

Screenshot 2023-08-07 at 20.47.02.png


Yes, expression's execution (debug == true) is delayed until expression is called. That makes sense. However, how is that special? If we go to my rewritten example:


Screenshot 2023-08-07 at 20.47.13.png

expression's execution is also delayed! It's actually very easy to test this. Let's add a few print statements to our  nonautoclosureAssert func.


As long as isDebug == false, none of the two print statements will execute. So, what gives? Why are Sundell and others (like this accepted answer from SO) describing autoclosures as ways of not evaluating a closure when it gets passed as a parameter? The accepted answer in that SO question goes:

“But in the normal calling scheme of a function in Swift, the arguments are evaluated before the function is called. If || was implemented in the obvious way:”

That is quite a statement! I had never heard this before. It cannot be true, as we just proved above. I'm passing two closures to nonautoclosureAssert and neither of them are evaluated. What gives?

Well, it seems that whoever answered that question (and Sundell) should add additional clarification about what delayed execution means. There's meaning overload when saying "delayed execution".

There's delayed execution like I achieved above when rewriting Sundell's example:

  • 1️⃣ A function or a closure is passed as a function parameter. It may or may not be evaluated later in the function. Hence, its execution is delayed.

And then there's delayed execution of the function parameter evaluation when the parameter is executing the closure:

  • 2️⃣ A function or a closure's result is passed as a function parameter. If the accepting parameter is marked as autoclosure, the execution is delayed.

In my code above, we've proved that autoclosure does not provide the benefit of point 1️⃣ above. Delaying the execution of a function or a closure passed as a function parameter can be achieved with or without autoclosure.

However! After hitting my head against the wall for a while, I've realized that everyone is talking about point 2️⃣ above. For example, the SO answer offers the following function:


And then passes along the result of executing the closure as part of the parameter, like so:

Screenshot 2023-08-07 at 20.48.20.png


If function || were designed as receiving a boolean, we would immediately crash:

Screenshot 2023-08-07 at 20.48.41.png


We would crash because execution of willCrash() must happen before the function is called. We must resolve the value of willCrash() before we can even call function ||.

On the other hand, if the function receives an autoclosure, willCrash() has delayed execution! Meaning, it doesn't need to be executed before we call the function. It will be neatly wrapped in a closure and sent along to the function in this new closure.

It's extremely important to note that this delay in execution provided by autoclosure (point 2️⃣) would not prevent a crash if we execute willCrash()!

With this knowledge, we can now understand that the original question doesn't make sense: What is the difference between an autoclosure and a closure that is evaluated depending on conditions?

The question I was asking was really: does autoclosure's delayed execution differ from passing in a function or a closure as function parameter? And now we know the answer is clearly: no, it doesn't differ at all. If we pass a function or a closure, execution is delayed. This is even explicitly laid out in the documentation – which I should've read first:

You get the same behavior of delayed evaluation when you pass a closure as an argument to a function.

In addition to other use cases, to me it's very clear that I want to use an autoclosure whenever I need to pass a closure's execution as a parameter without executing it immediately.

I hope that clarifies things. It certainly helped me understand why the initial value is passed as an autoclosure. For that context, go and buy the book.

References: