When converting from Objective-C to Swift, setters that can be returned to an optional value are marked as implicitly optional, so that you can reset them to their default value easily. But why not allow an optional setter, like this?
struct FooCollection {
subscript(index: Int) -> Element {
get { /* code */ }
optional set {
// newValue is Optional<Element>
}
}
}
This would also allow you to easily remove values from a Dictionary with a simple extension
You could also use this to remove more implicitly unwrapped optionals from the language with Objective-C type conversion.
// Before:
@MainActor class UIButton: UIControl {
// ...
var tintColor: UIColor! { get set }
}
// After:
@MainActor class UIButton: UIControl {
// ...
var tintColor: UIColor { get optional set }
}
What is supposed to be the non-optional value at the given index after the setter is invoked with nil as the new “value”?
You can already remove values from a dictionary via the key-based subscript by setting it to nil—note that if you subscript with a non-existent key, the getter returns nil.
Here again, what is supposed to be the non-optional value of tintColor after the user sets it to nil?
(Note that Swift deliberately rejects the idea of types having implicit default values, with limited exceptions (currently) when it comes to Optional.)
If your goal is that a nil value should be usable as a sentinel such that the setter can do as it pleases, this can be achieved currently using implicitly unwrapped optionals:
extension S {
subscript(index: Int) -> Element! {
get { ... }
set {
if let newValue { ... } else { ... }
}
}
}
Thanks to implicit unwrapping, callers can use the value returned from the getter essentially as though it's non-optional.
I think the example I provided is relatively common, I have heard several people find it annoying that the setter has to be optional here. Not sure if this use case alone warrants a new language feature though…
One thing you’d have to support is inout: a mutable subscript or property is supposed to have some base type where it’s valid to both get and set. That doesn’t conflict with optional setters, but does with optional getters (or arbitrary custom setter types). Of course, like with the set-only subscript proposal, we could give up on that principle and have the compiler error when there’s no “common” type that allows x = x to work (when x is inout). But that’s part of why the types aren’t fully independent, even if they could be more independent.
It won't help with subscripts, but you can accomplish this with a property wrapper for regular properties by providing a reset operation on the projection.
The biggest drawback is that you have to waste storage in the type to hold the default value, so between that and alignment padding, the struct in my example with two Doubles occupies 41 bytes
In upcoming versions of Swift, an attached macro would might work well for this, since the default value would be part of the macro's syntax transformation and encoded directly into the generated getter. That might even work for subscripts, as well.