[swift-evolution] [Proposal draft] Make Optional Requirements Objective-C-only

Xiaodi Wu xiaodi.wu at gmail.com
Sat Apr 23 11:40:34 CDT 2016


On Sat, Apr 23, 2016 at 4:51 AM, Michael Peternell <michael.peternell at gmx.at
> wrote:

> In my opinion, requiring something is almost never something that I would
> describe as a "feature".


I agree with this completely.


> I don't really care if the keyword is called "optional" or "objcoptional",
> I think both are fine, but I wouldn't want it to read "@objc optional". The
> "@objc" in "@objc optional" should be optional. Also, "@objc optional"
> seems to imply that there is something like "optional" without "@objc" as
> well.


Well, here is where I disagree. IMO, requiring this particular something
(i.e. @objc) is a feature, precisely because there *is* (conceptually)
optional without @objc. The point is to emphasize that it is a deliberate
choice not to support this possibility in Swift-only code.


> Maybe I go to a coffee house and order a coffee. After 15 minutes I ask
> when it will come. The waiter says that it will not come because I should
> have ordered a coffee "with caffeine". I complain: "but you didn't bring me
> any coffee at all". He said: "Yes, because we don't sell coffee without
> caffeine". "You should have said that", I replied angrily. So he explained
> it: "Our house is called 'real coffee contains caffeine', so I thought
> you'd know that" - "I understand." ;)
>

I think, rather, if we're going to use your analogy, that supporting
optional only in Obj-C is more like selling only coffee without caffeine.
And, it's been decided that it's not appropriate to sell coffee with
caffeine. Having a keyword named "optional" is like having a menu that
lists "coffee, $2" while only serving decaffeinated coffee. The problem
being addressed is that people read the menu outside the restaurant, enter
the restaurant because they want to drink coffee, then try to order coffee
only to learn from the waiter that it has no caffeine. Then people try to
propose that the restaurant sell coffee with caffeine, even though that has
already been proposed before and decided against. The proposal here is to
rewrite the menu so that it says "notreallycoffee, $2", and what I'm
suggesting is instead writing "decaffeinated coffee, $2" because it's
easier to read.


> To me, it's like a restaurant owner who complains that some customers say
> "please" while other customers don't. For better consistency, he now forces
> each customer to say "please" as well and to be polite. He also tried the
> opposite approach, by forbidding the word "please" in his rooms. But some
> polite customers became very unfriendly when he told them in a harsh tone
> to not use the "P-Word" here. So much for the Swiftian modest proposal ;)
>
> -Michael
>
> > Am 23.04.2016 um 03:02 schrieb Xiaodi Wu via swift-evolution <
> swift-evolution at swift.org>:
> >
> > ...assuming, of course, that you're putting forward a draft proposal
> about Swift that happens to be modest in scope, and not a Swiftian modest
> proposal.
> >
> >
> > On Fri, Apr 22, 2016 at 7:56 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
> > > 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 at 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 at swift.org
> > >> https://lists.swift.org/mailman/listinfo/swift-evolution
> > >>
> >
> > _______________________________________________
> > swift-evolution mailing list
> > swift-evolution at swift.org
> > https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160423/926a261e/attachment.html>


More information about the swift-evolution mailing list