Not an expert on Obj-C compatibility in Swift by any means, but this reads like it's largely a change of nomenclature. To me, though, `objcoptional` reads exceedingly poorly. Why not emphasize the Obj-C compatibility angle by requiring the `@objc` attribute to precede each use of `optional`? (In other words, effectively rename `optional` to `@objc optional`.)
On Fri, Apr 22, 2016 at 7:35 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote: > Proposal link: > https://github.com/DougGregor/swift-evolution/blob/objc-optional/proposals/NNNN-optional-requirements.md > > After a whole lot of discussion and thrashing on optional requirements, I > have a draft for a modest proposal: change the ‘optional’ keyword to > something that indicates that this feature is only for compatibility with > Objective-C and will not be supported on Swift protocols. Comments welcome! > > - Doug > > Make Optional Requirements Objective-C-only > > Proposal: SE-NNNN > Author(s): Doug Gregor > Status: Awaiting review > Review manager: TBD > > Introduction > > Swift currently has support for "optional" requirements in Objective-C > protocols, to match with the corresponding feature of Objective-C. We don't > want to make optional requirements a feature of Swift protocols (for reasons > described below), nor can we completely eliminate the notion of the language > (for different reasons also described below). Therefore, to prevent > confusion about our direction, this proposal changes the optional keyword > objcoptional to indicate that this is an Objective-C compatibility feature. > > Swift-evolution threads: eliminate optional requirements, make Swift > protocols support optional requirements and make optional protocol > requirements first class citizens. > > Motivation > > Having optional only work for Objective-C requirements is very weird: it > feels like a general feature with a compiler bug that prevents it from > working generally. However, we don't want to make it a feature of Swift > protocols and we can't eliminate it (see alternatives considered), so we > propose to rename the keyword to make it clear that this feature is intended > only for compatibility with Objective-C. > > Proposed solution > > Rename the optional contextual keyword to objcoptional. Note that: > > It would read better as objc_optional or objcOptional, but keywords in Swift > run the words together, and > > It should not be an attribute @objcOptional because it changes the effective > type of the declaration. Referencing an optional requirement wraps the > result in one more level of optional, which is used to test whether the > requirement was implemented. > > This means that: > > @objc protocol NSTableViewDelegate { > optional func tableView(_: NSTableView, viewFor: NSTableColumn, row: Int) > -> NSView? > optional func tableView(_: NSTableView, heightOfRow: Int) -> CGFloat > } > > becomes: > > @objc protocol NSTableViewDelegate { > objcoptional func tableView(_: NSTableView, viewFor: NSTableColumn, row: > Int) -> NSView? > objcoptional func tableView(_: NSTableView, heightOfRow: Int) -> CGFloat > } > > Impact on existing code > > Any code that declares @objc protocols with optional requirements will need > to be changed to use the objcoptionalkeyword. However, it is trivial for the > migrator to update the code and for the compiler to provide Fix-Its, so the > actual impact on users should be small. > > Alternatives considered > > It's a fairly common request to make optional requirements work in Swift > protocols (as in the aforementioned threads, hereand here). However, such > proposals have generally met with resistance because optional requirements > have significant overlap with other protocol features: "default" > implementations via protocol extensions and protocol inheritance. For the > former case, the author of the protocol can provide a "default" > implementation via a protocol extension that encodes the default case > (rather than putting it at the call site). In the latter case, the protocol > author can separate the optional requirements into a different protocol that > a type can adopt to opt-in to whatever behavior they customize. While not > exactlythe same as optional requirements, which allow one to perform > per-requirement checking to determine whether the type implemented that > requirement, the gist of the threads is that doing so is generally > considered an anti-pattern: one would be better off factoring the protocol > in a different way. Therefore, we do not propose to make optional > requirements work for Swift protocols. > > The second alternative would be to eliminate optional requirements entirely > from the language. The primary challenge here is Cocoa interoperability, > because Cocoa's protocols (primarily delegates and data sources) have a > large number of optional requirements that would have to be handled somehow > in Swift. These optional requirements would have to be mapped to some other > construct in Swift, but the code generation model must remain the same > because the Cocoa frameworks rely on the ability to ask the question "was > this requirement implemented by the type?" in Objective-C code at run time. > > The most popular approach to try to map optional requirements into existing > Swift constructs is to turn an optional method requirement into a property > of optional closure type. For example, this Objective-C protocol: > > @protocol NSTableViewDelegate > @optional > - (nullable NSView *)tableView:(NSTableView *)tableView > viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row; > - (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row; > @end > > which currently imports into Swift as: > > @objc protocol NSTableViewDelegate { > optional func tableView(_: NSTableView, viewFor: NSTableColumn, row: Int) > -> NSView? > optional func tableView(_: NSTableView, heightOfRow: Int) -> CGFloat > } > > would become, e.g., > > @objc protocol NSTableViewDelegate { > var tableView: ((NSTableView, viewFor: NSTableColumn, row: Int) -> > NSView?)? { get } > var tableView: ((NSTableView, heightOfRow: Int) -> CGFloat)? { get } > } > > Unfortunately, this introduces an overloaded property named tableView. To > really make this work, we would need to introduce the ability for a property > to have a compound name, which would also let us take the labels out of the > function type: > > @objc protocol NSTableViewDelegate { > var tableView(_:viewFor:row:): ((NSTableView, NSTableColumn, Int) -> > NSView?)? { get } > var tableView(_:heightOfRow:): ((NSTableView, Int) -> CGFloat)? { get } > } > > By itself, that is a good feature. However, we're not dont, because we would > need yet another extension to the language: one would want to be able to > provide a method in a class that is used to conform to a property in the > protocol, e.g., > > class MyDelegate : NSObject, NSTableViewDelegate { > func tableView(_: NSTableView, viewFor: NSTableColumn, row: Int) -> > NSView? { ... } > func tableView(_: NSTableView, heightOfRow: Int) -> CGFloat { ... } > } > > Indeed, the Objective-C implementation model effectively requires us to > satisfy these property-of-optional-closure requirements with methods so that > Objective-C clients can use -respondsToSelector:. In other words, one would > not be able to implement these requirements in by copy-pasting from the > protocol to the implementing class: > > class MyDelegate : NSObject, NSTableViewDelegate { > // Note: The Objective-C entry points for these would return blocks, which > is incorrect > var tableView(_:viewFor:row:): ((NSTableView, NSTableColumn, Int) -> > NSView?)? { return ... } > var tableView(_:heightOfRow:): ((NSTableView, Int) -> CGFloat)? { return > ... } > } > > That is both a strange technical restriction that would be limited to > Objective-C protocols and a serious usability problem: the easiest way to > stub out the contents of your type when it conforms to a given protocol is > to copy the declarations from the protocol into your type, then fill in the > details. This change would break that usage scenario badly. > > There have been other ideas to eliminate optional requirements. For example, > Objective-C protocols could be annotated with attributes that say what the > default implementation for each optional requirement is (to be used only in > Swift), but such a massive auditing effort is impractical. There is a > related notion of caller-site default implementations that was not > well-received due to its complexity. > > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org > https://lists.swift.org/mailman/listinfo/swift-evolution > _______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution