Relaying a question from StackOverflow here, on behalf of a user who doesn't appear to be able to access the forums directly: why does assigning to a mutable @optional
Objective-C protocol property result in a Swift compilation error? (Reading from it does not.)
The original SO question has the full example, but it can be simplified down to the following "pure" Swift on Darwin platforms:
import Foundation
@objc protocol Foo {
@objc /* optional */ var bar: Any { get set }
}
func foo(_ f: Foo) {
print(f.bar)
f.bar = 42
}
When Foo.bar
is not marked as optional
, the above compiles as expected. When Foo.bar
is marked as optional
, the code no longer compiles:
print(f.bar) // warning: Expression implicitly coerced from 'Any?' to 'Any'
f.bar = 42 // error: Cannot assign to property: 'f' is a 'let' constant
The warning is expected: since the property is optional
, the getter may not be present, so f.bar
is wrapped in a layer of optionality which returns nil
when the property is not implemented. The error, however, is a bit surprising, since f
is necessarily an object.
Some iteration:
-
More explicitly constraining
Foo
toAnyObject
(in case this somehow hits another code path) does not change the diagnostic, nor does deriving fromNSObjectProtocol
-
Introducing an explicitly-mutable intermediate variable does change the diagnostic, but not the result:
var g = f g.bar = 42 // error: Cannot assign to property: 'g' is immutable
Is there a reason for this being the case? My gut feeling is that this is likely a very niche edge case that isn't quite handled, but poking through SE-0070 and associated proposals + threads didn't bring up anything seemingly definitive. (Theoretically, it does seem possible to me to model writing to an optional var
the same as calling an optional
method, and simply no-op'ing if the setter isn't implemented, but again, this does appear to be pretty niche, and the proposal does pretty clearly call out optional
requirements as explicitly for compatibility only.)
If there's anything more explicitly documented somewhere that I've missed, I'd be very curious to know!
(/cc @Douglas_Gregor as the author of SE-0070, in case you remember)
(As an aside, this does compile in pure Objective-C, of course with the caveat that if you don't implement Foo.bar
, assignment will trigger an unrecognized selector exception on -setBar:
.)