Are optional closures escaping or not? 🤨
Hi 👋
This newsletter keeps growing: there are now more than 2,8k subscribers!
(2,842 as I’m writing this, to be exact 🤓)
This is making me very happy and I’m hoping to reach 3k by the end of the year 🤞
If you want you can help me reach this goal by sharing this article with some of your iOS colleagues ❤️
And now before we go into the topic of this email, I have a big thank you to my sponsor for another week: Bitrise 🤖
Advertisement
Sponsors like Bitrise really help me grow my content creation, so if you have time please make sure to check out their survey: it’s a direct support to my content creation ☺️
It had been a long time since I had asked a quiz question on social media!
So last week I went ahead and asked this question, about the semantics of optional closures in Swift:
an escaping closure 🤨
a non-escaping closure 😌
what’s escaping? 🤷🏻♂️
And here are the results of the poll on Twitter…
…and on LinkedIn:
What’s interesting here is that we can see this question is really getting people confused!
Each platform is split almost equally between the two answers, with only a small majority each time.
So since we can’t rely on public opinion, how can we find the answer to that question?
The easiest way to do it is by running a small experiment.
You probably know that, since escaping closures can lead to retain cycles, the compiler forces us to explicitly capture self
inside such closures.
So how about we write code that uses self
without explicitly capturing it inside an optional closure, and see what the compiler has to say about it?
Here’s such a piece of code:
When we try to build this code, two options are possible:
The code builds successfully, which means that optional closures are non-escaping
We get a compilation error, because we haven’t explicitly captured
self
, which means that optional closures are escaping
So let’s see what happens!
As you can see, we do get a compilation error regarding our use of self
inside the closure.
And as soon as we explicitly capture self
, the error goes away:
So we have our answer: optional closures are indeed escaping in Swift!
Now the question that comes next is: why is it the case?
And why isn’t Swift forcing us to use the attribute @escaping
?
To answer these new questions, we need to talk a bit about types:
() -> Void
is a function type in Swift.
As such, it would be possible to apply the attribute @escaping
to it.
However, (() -> Void)?
is not a function type!
It’s equivalent to the type Optional<() -> Void>
, and if we look at how Optional
is implemented…
…we can see it’s implemented using an enum
.
But the attribute @escaping
can only be applied to a function, and not to an enum
!
So that’s why the attribute @escaping
couldn’t be used in the signature of function.
Moreover, since the closure is stored in the associated value of the case
some()
, it does behave like an escaping closure and the compiler is able to understand it.
Which leads to this peculiar situation: optional closures do behave like escaping closures, even though the attribute @escaping
is never used anywhere in their declaration 🤯
That’s all for this topic, I hope you’ve enjoyed learning about this tricky behavior of Swift!
If you know other examples of similarly tricky syntaxes, please share them with me: I’d love to hear about them 😀
That’s all for this email, thanks for reading it!
If you’ve enjoyed it, feel free to forward it
to your friends and colleagues 🙌
I wish you an amazing week!
❤️