I mean, if the compiler forces one to add the notation, then it seems to me that it already understands it is an escaping block.
Why then force the programmer to add it?
Danks
I mean, if the compiler forces one to add the notation, then it seems to me that it already understands it is an escaping block.
Why then force the programmer to add it?
Danks
It’s part of the public API of your function. Changing from a non-escaping to an escaping closure is a breaking change.
The annotation exists to make that explicit.
Here's an example of it being a breaking change:
func f(_ closure: /* @escaping */ () -> Void) {
closure()
}
struct AStruct {
var i = 0
mutating func mutate() {
f { i += 1 }
}
}
If f takes a non-escaping closure, all is well. But if you make it @escaping, you get error: escaping closure captures mutating 'self' parameter.
There are several other possible errors related to closure captures being able to effectively make structs into reference types (thereby destroying any guarentees that come from being a value-type)
You need @escaping to differentiate the type of closure because:
not all closures are “escaping” (sure, we use that escaping pattern for asynchronous methods, but for functional programming patterns, closures are generally non-escaping); and
there are certain optimizations (e.g., how it handles memory calls behind the scenes) that the compiler can do with non-escaping closures that are not possible with escaping ones.
Bottom line, the @escaping qualifier is necessary to let the compiler to know which optimizations it can do.
Besides, we should always be able to look at an interface and easily deduce whether the closure is escaping or not. In the absence of some qualifier, it would be much harder to reason about one’s code.
FWIW, because non-escaping closures do not introduce the same sort of strong reference cycle risks that escaping ones do, the compiler permits more natural references to properties in non-escaping closures in comparison to escaping closures. By including/excluding the @escaping qualifier, the compiler also knows how to handle self references inside the closure.
In the distant past, closures defaulted to escaping and we had to annotate the non-escaping ones with @noescape. Then, as a result of SE-0103, the default for closures changed to non-escaping, thereby deprecating the old @noescape annotation, but requiring us to annotate escaping closures with @escaping.