CODEX

Swift: Demystifying Autoclosures

Learn what the mysterious @autoclosure is and how to use it in Swift.

Artturi Jalli
Mar 6 · 4 min read
Photo by Caspar Camille Rubin on Unsplash

Autoclosures in Swift

An autoclosure works by automatically wrapping a function argument in a closure. An autoclosure itself does not accept any arguments. When an autoclosure is called, it returns the value of the expression wrapped inside of it.

Before diving any deeper, it is important to notice what Apple has to say about autoclosures:

It’s common to call functions that take autoclosures, but it’s not common to implement that kind of function.

Overusing autoclosures can make your code hard to understand. The context and function name should make it clear that evaluation is being deferred.

This highlights the fact that autoclosures are rarely that beneficial and most of the time you should not implement functions using them. However, they can be useful in some very specific cases.

What’s the Benefit of an Autoclosure

On rare occasions, it is syntactically convenient to use an autoclosure when working with a function that takes a closure argument. This is simply because using an autoclosure allows you to omit curly braces, {}.

This is best demonstrated by an example. Let’s create a function that takes a closure as its argument:

func I_will(_ perform_action: () -> Void) {
perform_action()
}

To e.g. print something with this function, you can call it by passing in a closure. Remember that you need to wrap the closure inside curly braces:

I_will({
print("Hello, world!")
})

This works just fine, but one could argue that the syntax is a bit off. Wouldn’t it be nicer if you could just write I_will(print(“Hello, world”)) instead?

In order to achieve this, you can modify I_will function to accept an @autoclosure:

func I_will(_ perform_action: @autoclosure () -> Void) {
perform_action()
}

Now you are able to call the function simply by:

I_will(print("Hello, world"))

But how does that work? The function I_will expects a closure of type () -> Void but you are passing in a print statement that returns Void…?

It works because autoclosure wraps print("Hello, world!") inside a closure automatically. This simply means that Void becomes () -> Void behind the scenes. And when the function finally calls this autoclosure, it just returns what is wrapped inside of it.

It is that simple. Now you know what autoclosures are and how they work.

Next, let’s take a look at some built-in functionality that utilizes autoclosures.

Assert

You might be familiar with the built-in assert function in Swift:

assert(1 == 2, "This condition failed")

Let’s take a look at the implementation of assert:

As you can see, the parameterscondition and message are autoclosures. As you already know, autoclosures allow omitting curly braces. So using an autoclosure is a trivial choice from Apple because:

assert(1 == 2, "This condition failed")

looks better / is cleaner than

assert({ 1 == 2 }, { "This condition failed" })

This still might leave you wondering why does assert expect closures in the first place? Couldn’t the condition and message just be a regular Bool and a String?

By using closures, one can delay the evaluation as the closure is not run before it is called. If there’s no reason to run the closure, one can save resources simply by not calling it.

As you might know, asserting works with debug builds only. So if you make an assert call in an invalid context, there is no reason for the assert function to evaluate condition or message closures as it won’t need their result.

However, if condition and message were not closures they’d always be evaluated no regardless of the conditions. This would just waste resources for no reason when calling assert from where it doesn’t work.

In short, when implementing assert, Apple decided to help saving resources by accepting closure arguments that are evaluated only when necessary. To make the syntax clean, they replaced closures with autoclosures.

Conclusion

An autoclosure wraps an argument around a closure. An autoclosure itself does not accept arguments. When calling an autoclosure, it returns the result of the expression wrapped inside of it.

It is common to call functions that use autoclosures but they are something you rarely need/want to implement yourself.

Using a lot of autoclosures can make code confusing.

In some very specific situations, it might be syntactically beneficial to use an autoclosure.

That’s it!

I hope you find it useful. Give it some claps in order to make others find it too! Make sure you follow me on Medium not to miss anything.

Also, let’s be friends on Linkedin.

CodeX

Everything connected with Tech & Code

Artturi Jalli

Written by

Tech Expert, Entrepreneur, Software Engineer from Finland. Writing about programming and science. Check out my blog at https://www.codingem.com/

CodeX

CodeX

Everything connected with Tech & Code

Artturi Jalli

Written by

Tech Expert, Entrepreneur, Software Engineer from Finland. Writing about programming and science. Check out my blog at https://www.codingem.com/

CodeX

CodeX

Everything connected with Tech & Code

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store