Thanks, I had never realised this issue existed!
I don't appreciate much how @unrequired
would create a redundant way of expressing optionality in Swift, and IMO there is nothing wrong per se with the Optional
type being an enum.
I think the issue we encounter is that while the special compiler support the Optional
type benefits from is a good thing (eg: gives us the nice T?
syntax instead of Optional<T>
, avoids us from explicitly setting optional properties to nil
or .none
) it still has some gaps that need to be filled, one I have in mind is this one @codafi recently mentioned.
IMO we should either build into the compiler the additional logic required to handle this specific case for when closures are optional, or another option could be to introduce a new attribute that would also be applicable to other types, which could be useful on the ones that are primarily containers.
The attribute could be named something such as @propagatesEscape
that would be used this way:
@propagatesEscape
enum Optional<Wrapped> { ... }
But also on other types:
@propagatesEscape
struct Array<Element> { ... }
This way, any time you would use them with a type requiring the explicit @escaping
attribute, they would themselves start requiring it if they are escaped, for instance:
struct Foo<T> {
var x: [(Int)->(String)]
init(x: [(Int)->(String)]) {
self.x = x // Assigning non-escaping parameter 'x' to an escaping container type
}
}
struct Bar<T> {
var x: ((Int)->(String))?
init(x: ((Int)->(String))?) {
self.x = x // Error: Assigning non-escaping parameter 'x' to an escaping container type
}
}
The correct way to write this would now be to do that:
struct Bar<T> {
var x: ((Int)->(String))?
init(x: @escaping ((Int)->(String))?) {
self.x = x
}
}
What do you think about this? I don't know what drawbacks this approach might have.
This would be a source breaking change, so maybe it could be made a warning during one or two years before becoming an error?