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


(Douglas Gregor) #1

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 <https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-optional-requirements.md>
Author(s): Doug Gregor <https://github.com/DougGregor>
Status: Awaiting review
Review manager: TBD
<https://github.com/DougGregor/swift-evolution/blob/objc-optional/proposals/NNNN-optional-requirements.md#introduction>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 <http://thread.gmane.org/gmane.comp.lang.swift.evolution/14046>, make Swift protocols support optional requirements <http://thread.gmane.org/gmane.comp.lang.swift.devel/1316> and make optional protocol requirements first class citizens <http://thread.gmane.org/gmane.comp.lang.swift.evolution/13347>.

<https://github.com/DougGregor/swift-evolution/blob/objc-optional/proposals/NNNN-optional-requirements.md#motivation>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 <https://github.com/DougGregor/swift-evolution/blob/objc-optional/proposals/NNNN-optional-requirements.md#alternatives-considered>), so we propose to rename the keyword to make it clear that this feature is intended only for compatibility with Objective-C.

<https://github.com/DougGregor/swift-evolution/blob/objc-optional/proposals/NNNN-optional-requirements.md#proposed-solution>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
}
<https://github.com/DougGregor/swift-evolution/blob/objc-optional/proposals/NNNN-optional-requirements.md#impact-on-existing-code>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.

<https://github.com/DougGregor/swift-evolution/blob/objc-optional/proposals/NNNN-optional-requirements.md#alternatives-considered>Alternatives considered

It's a fairly common request to make optional requirements work in Swift protocols (as in the aforementioned threads, here <http://thread.gmane.org/gmane.comp.lang.swift.devel/1316>and here <http://thread.gmane.org/gmane.comp.lang.swift.evolution/13347>). 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 <http://thread.gmane.org/gmane.comp.lang.swift.evolution/14046> that was not well-received due to its complexity.


(Xiaodi Wu) #2

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


(Daniel Duan) #3

I think this change actually *increases* readability since it made the intend of the keyword clearer.

+1

Daniel Duan

···

Sent from my iPhone

On Apr 22, 2016, at 5:56 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> 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@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


(Xiaodi Wu) #4

...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
<https://en.wikipedia.org/wiki/A_Modest_Proposal>.

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`.)

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

···

On Fri, Apr 22, 2016 at 7:56 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Fri, Apr 22, 2016 at 7:35 PM, Douglas Gregor via swift-evolution > <swift-evolution@swift.org> wrote:

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


(Douglas Gregor) #5

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`.)

That is a great idea.

···

Sent from my iPhone

On Apr 22, 2016, at 5:56 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

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


(Michael Peternell) #6

In my opinion, requiring something is almost never something that I would describe as a "feature". 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. 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." :wink:

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 :wink:

-Michael

···

Am 23.04.2016 um 03:02 schrieb Xiaodi Wu via swift-evolution <swift-evolution@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@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@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


(Chris Lattner) #7

Doesn’t this have the same problem as the current (Swift 1/2) implementation? People will continue to believe that it is a bug that you must specify @objc.

-Chris

···

On Apr 22, 2016, at 8:02 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

Sent from my iPhone

On Apr 22, 2016, at 5:56 PM, Xiaodi Wu <xiaodi.wu@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`.)

That is a great idea.


(Xiaodi Wu) #8

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." :wink:

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.

···

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

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 :wink:

-Michael

> Am 23.04.2016 um 03:02 schrieb Xiaodi Wu via swift-evolution < > swift-evolution@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@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@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


(Xiaodi Wu) #9

Perhaps they will, but IMO it's an improvement. In the current
implementation, `optional func` is spatially divorced from the `@objc`
annotation on the containing protocol. There's nothing in the code that
helps you to deduce that the two are tied to each other in some way. With
an immediate juxtaposition, it's much more explicable that optional
functions must be @objc functions. To my mind, it reads similarly to how
throwing functions must be called with some sort of `try`.

(FWIW, my hunch is that if the keyword were named `objcoptional` to begin
with, you'd still have people proposing to extend optional requirements to
pure-Swift protocols and renaming the keyword `optional`.)

···

On Sun, Apr 24, 2016 at 4:28 PM, Chris Lattner <clattner@apple.com> wrote:

> On Apr 22, 2016, at 8:02 PM, Douglas Gregor via swift-evolution < > swift-evolution@swift.org> wrote:
>
>
>
> Sent from my iPhone
>
>> On Apr 22, 2016, at 5:56 PM, Xiaodi Wu <xiaodi.wu@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`.)
>
> That is a great idea.

Doesn’t this have the same problem as the current (Swift 1/2)
implementation? People will continue to believe that it is a bug that you
must specify @objc.


(Erica Sadun) #10

I thought I'd throw a few ideas into the mix. I'm arriving late to the discussion. (I didn't expect the conversation to last this long.) I did take a quick look back through the thread but I may have missed some bits along the way. Apologies in advance for any redundancy:

* Optional requirement is an oxymoron. (This is a redux of my previous contribution to this topic but it's a good starting point.)

* Swift's "optional" protocol implementations are no such thing. They are default implementations that can be overridden. (Tangentially, why not introduce a required "override" keyword for conforming types that implement a version of a member introduced in protocol extensions? This would match the class approach and enhance safety and intent.)

* Swift already has an `Optional` type. Importing ObjC "optional" protocol requirements is therefore semantically problematic from a Swift development POV. I don't like either the "@objcoptional" or "@objc optional" solutions mentioned upthread. They overload "optional" syntactically and confuse semantics. I think the key words that better describe what's happening in, for example, a `UITableViewDelegate`, are "discretionary" or "elective" implementations. Swift has renamed lots of Objective C things (waves hi to SE-0005 <https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md>). Why not "optional"?

* I do *support* retaining `@objc` in some form and I believe it can be addressed in a way that does not appear to be a bug. "Optional protocol conformance" is a behavior that is external to the language. I do not believe would be voluntarily added to Swift should the topic arise. Therefore I find it insufficient to introduce attributes like `@elective` or `@discretionary` in order to satisfy non-native requirements. I would prefer to see the @objc attribute be extended to support these and any future Objective-C-specific behaviors: @objc(elective), @objc(importedProtocolSupport: elective), or whatever. While these are wordy, I assume like any other Swift attributes they can be placed on a line before the function declaration, and it would be instantly clear why they've been placed there, and they would not overlap with Swift semantics *or* expectations. I leave the color of the bikeshed as an exercise for the reader.

-- Erica

···

On Apr 24, 2016, at 3:28 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 22, 2016, at 8:02 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

Sent from my iPhone

On Apr 22, 2016, at 5:56 PM, Xiaodi Wu <xiaodi.wu@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`.)

That is a great idea.

Doesn’t this have the same problem as the current (Swift 1/2) implementation? People will continue to believe that it is a bug that you must specify @objc.

-Chris


(Dave Abrahams) #11

Doesn't that argue for @objc(optional)

?

···

on Sun Apr 24 2016, Chris Lattner <swift-evolution@swift.org> wrote:

On Apr 22, 2016, at 8:02 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

Sent from my iPhone

On Apr 22, 2016, at 5:56 PM, Xiaodi Wu <xiaodi.wu@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`.)

That is a great idea.

Doesn’t this have the same problem as the current (Swift 1/2)
implementation? People will continue to believe that it is a bug that
you must specify @objc.

--
Dave


(Douglas Gregor) #12

>
>
>
> Sent from my iPhone
>
>>
>> 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`.)
>
> That is a great idea.

Doesn’t this have the same problem as the current (Swift 1/2) implementation? People will continue to believe that it is a bug that you must specify @objc.

Perhaps they will, but IMO it's an improvement. In the current implementation, `optional func` is spatially divorced from the `@objc` annotation on the containing protocol. There's nothing in the code that helps you to deduce that the two are tied to each other in some way. With an immediate juxtaposition, it's much more explicable that optional functions must be @objc functions.

Yeah. I also think the diagnostic will be part of the messaging. If you leave off the @objc, the compiler can have an error along the lines of "optional requirements are an Objective-C compatibility feature; add '@objc'

···

Sent from my iPhone

On Apr 24, 2016, at 3:24 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Sun, Apr 24, 2016 at 4:28 PM, Chris Lattner <clattner@apple.com> wrote:
> On Apr 22, 2016, at 8:02 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:
>> On Apr 22, 2016, at 5:56 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

To my mind, it reads similarly to how throwing functions must be called with some sort of `try`.

(FWIW, my hunch is that if the keyword were named `objcoptional` to begin with, you'd still have people proposing to extend optional requirements to pure-Swift protocols and renaming the keyword `optional`.)


(Xiaodi Wu) #13

I think there are some good points here. As a riff, though, I'd argue that
Obj-C optional should *not* be renamed to elective or something else.
Renaming, so far, has been for the purpose of providing first-class Swifty
idioms for existing things. It makes moving between Swift-native code and
legacy code more seamless and encourages increased use of what's being
renamed. However, here we have something that we all agree isn't and cannot
be a Swift idiom. Yes, it's true that the name clashes with Swift optional,
but the very thing itself also clashes with how protocols requirements are
intended to work in Swift. It *shouldn't* look like a first-class Swift
concept.

···

On Sun, Apr 24, 2016 at 9:07 PM Erica Sadun via swift-evolution < swift-evolution@swift.org> wrote:

On Apr 24, 2016, at 3:28 PM, Chris Lattner via swift-evolution < > swift-evolution@swift.org> wrote:

On Apr 22, 2016, at 8:02 PM, Douglas Gregor via swift-evolution < > swift-evolution@swift.org> wrote:

Sent from my iPhone

On Apr 22, 2016, at 5:56 PM, Xiaodi Wu <xiaodi.wu@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`.)

That is a great idea.

Doesn’t this have the same problem as the current (Swift 1/2)
implementation? People will continue to believe that it is a bug that you
must specify @objc.

-Chris

I thought I'd throw a few ideas into the mix. I'm arriving late to the
discussion. (I didn't expect the conversation to last this long.) I did
take a quick look back through the thread but I may have missed some bits
along the way. Apologies in advance for any redundancy:

* Optional requirement is an oxymoron. (This is a redux of my previous
contribution to this topic but it's a good starting point.)

* Swift's "optional" protocol implementations are no such thing. They are
default implementations that can be overridden. (Tangentially, why not
introduce a required "override" keyword for conforming types that implement
a version of a member introduced in protocol extensions? This would match
the class approach and enhance safety and intent.)

* Swift already has an `Optional` type. Importing ObjC "optional" protocol
requirements is therefore semantically problematic from a Swift development
POV. I don't like either the "@objcoptional" or "@objc optional" solutions
mentioned upthread. They overload "optional" syntactically and confuse
semantics. I think the key words that better describe what's happening in,
for example, a `UITableViewDelegate`, are "*discretionary*" or "*elective*"
implementations. Swift has renamed lots of Objective C things (waves hi to
SE-0005
<https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md>).
Why not "optional"?

* I do *support* retaining `@objc` in some form and I believe it can be
addressed in a way that does not appear to be a bug. "Optional protocol
conformance" is a behavior that is external to the language. I do not
believe would be voluntarily added to Swift should the topic arise.
Therefore I find it insufficient to introduce attributes like `@elective`
or `@discretionary` in order to satisfy non-native requirements. I would
prefer to see the @objc attribute be extended to support these and any
future Objective-C-specific behaviors: @objc(elective),
@objc(importedProtocolSupport: elective), or whatever. While these are
wordy, I assume like any other Swift attributes they can be placed on a
line before the function declaration, and it would be instantly clear why
they've been placed there, and they would not overlap with Swift semantics
*or* expectations. I leave the color of the bikeshed as an exercise for the
reader.

-- Erica

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Douglas Gregor) #14

Sent from my iPhone

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`.)

That is a great idea.

Doesn’t this have the same problem as the current (Swift 1/2) implementation? People will continue to believe that it is a bug that you must specify @objc.

-Chris

I thought I'd throw a few ideas into the mix. I'm arriving late to the discussion. (I didn't expect the conversation to last this long.) I did take a quick look back through the thread but I may have missed some bits along the way. Apologies in advance for any redundancy:

* Swift's "optional" protocol implementations are no such thing. They are default implementations that can be overridden.

(Pulling this one out first). When I read “a default implementation that can be overridden”, I think of the conforming type *or a subclass thereof* providing a different implementation from the default. “Optional” requirements are things that the conforming type does not have to provide…. and a user of the protocol must cope with conforming types that don’t provide them.

(Tangentially, why not introduce a required "override" keyword for conforming types that implement a version of a member introduced in protocol extensions? This would match the class approach and enhance safety and intent.)

This is a commonly-requested feature that I don’t think we need. The TL;DR version is that I feel like specifying the conformance explicitly (my type Foo conforms to protocol P) already expresses intent, and the compiler should help with the rest. I’ve recently been working on providing better warnings for cases where one has tried to implement an optional requirement for a protocol (but got the declaration wrong), and I think we can turn it on for cases where one got a default implementation instead:

  http://thread.gmane.org/gmane.comp.lang.swift.devel/1799

* Optional requirement is an oxymoron. (This is a redux of my previous contribution to this topic but it's a good starting point.)

* Swift already has an `Optional` type. Importing ObjC "optional" protocol requirements is therefore semantically problematic from a Swift development POV. I don't like either the "@objcoptional" or "@objc optional" solutions mentioned upthread. They overload "optional" syntactically and confuse semantics. I think the key words that better describe what's happening in, for example, a `UITableViewDelegate`, are "discretionary" or "elective" implementations. Swift has renamed lots of Objective C things (waves hi to SE-0005 <https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md>). Why not "optional”?

If we were adding optional requirements to Swift protocols, I would agree that it makes sense to change the nomenclature to avoid the oxymoron and the confusion with optionals. However, since this is now moving into the realm of “Objective-C compatibility feature”, I think it’s reasonable to retain the existing, Objective-C terminology.

Also, there is a link between the Optional type and optional requirements: when you reference an optional requirement, you get back an Optional.

* I do *support* retaining `@objc` in some form and I believe it can be addressed in a way that does not appear to be a bug. "Optional protocol conformance" is a behavior that is external to the language. I do not believe would be voluntarily added to Swift should the topic arise.

It’s a feature that exists to support compatibility with another language; we would not add it if it not for Objective-C. However, it is a real language feature with different semantics from other language features.

Therefore I find it insufficient to introduce attributes like `@elective` or `@discretionary` in order to satisfy non-native requirements. I would prefer to see the @objc attribute be extended to support these and any future Objective-C-specific behaviors: @objc(elective), @objc(importedProtocolSupport: elective), or whatever. While these are wordy, I assume like any other Swift attributes they can be placed on a line before the function declaration, and it would be instantly clear why they've been placed there, and they would not overlap with Swift semantics *or* expectations. I leave the color of the bikeshed as an exercise for the reader.

Do remember that @objc(something) already has a meaning: it gives the Objective-C name “something” to the entity that the @objc(something) describes.

  - Doug

···

On Apr 24, 2016, at 7:02 PM, Erica Sadun <erica@ericasadun.com> wrote:

On Apr 24, 2016, at 3:28 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Apr 22, 2016, at 8:02 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Apr 22, 2016, at 5:56 PM, Xiaodi Wu <xiaodi.wu@gmail.com <mailto:xiaodi.wu@gmail.com>> wrote:


(Xiaodi Wu) #15

That was my first instinct as well, but I'm persuaded by Doug's points on
the issue, which I'll just quote below because he puts it much better than
I could:
* "It shouldn't be an attribute because it changes the type signature of
references to the requirement."
* "Do remember that @objc(something) already has a meaning: it gives the
Objective-C name “something” to the entity that the @objc(something)
describes."

···

On Mon, Apr 25, 2016 at 5:08 PM, Dave Abrahams via swift-evolution < swift-evolution@swift.org> wrote:

on Sun Apr 24 2016, Chris Lattner <swift-evolution@swift.org> wrote:

>> On Apr 22, 2016, at 8:02 PM, Douglas Gregor via swift-evolution < > swift-evolution@swift.org> wrote:
>>
>>
>>
>> Sent from my iPhone
>
>>
>>> On Apr 22, 2016, at 5:56 PM, Xiaodi Wu <xiaodi.wu@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`.)
>>
>> That is a great idea.
>
> Doesn’t this have the same problem as the current (Swift 1/2)
> implementation? People will continue to believe that it is a bug that
> you must specify @objc.

Doesn't that argue for @objc(optional)

?


(Erica Sadun) #16

* Swift already has an `Optional` type. Importing ObjC "optional" protocol requirements is therefore semantically problematic from a Swift development POV. I don't like either the "@objcoptional" or "@objc optional" solutions mentioned upthread. They overload "optional" syntactically and confuse semantics. I think the key words that better describe what's happening in, for example, a `UITableViewDelegate`, are "discretionary" or "elective" implementations. Swift has renamed lots of Objective C things (waves hi to SE-0005 <https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md>). Why not "optional”?

If we were adding optional requirements to Swift protocols, I would agree that it makes sense to change the nomenclature to avoid the oxymoron and the confusion with optionals. However, since this is now moving into the realm of “Objective-C compatibility feature”, I think it’s reasonable to retain the existing, Objective-C terminology.

Also, there is a link between the Optional type and optional requirements: when you reference an optional requirement, you get back an Optional.

Fair enough point but one that doesn't really sway me enough to include a native keyword for an ObjC compatibility feature.

* I do *support* retaining `@objc` in some form and I believe it can be addressed in a way that does not appear to be a bug. "Optional protocol conformance" is a behavior that is external to the language. I do not believe would be voluntarily added to Swift should the topic arise.

It’s a feature that exists to support compatibility with another language; we would not add it if it not for Objective-C. However, it is a real language feature with different semantics from other language features.

Sounds like we're agreed on this point.

Therefore I find it insufficient to introduce attributes like `@elective` or `@discretionary` in order to satisfy non-native requirements. I would prefer to see the @objc attribute be extended to support these and any future Objective-C-specific behaviors: @objc(elective), @objc(importedProtocolSupport: elective), or whatever. While these are wordy, I assume like any other Swift attributes they can be placed on a line before the function declaration, and it would be instantly clear why they've been placed there, and they would not overlap with Swift semantics *or* expectations. I leave the color of the bikeshed as an exercise for the reader.

Do remember that @objc(something) already has a meaning: it gives the Objective-C name “something” to the entity that the @objc(something) describes.

And this is something I *did* overlook. Is there leeway to add labeled items `@objc(x: y)`? If so, `@objc(something)` could transition to `@objc(somelabel: something)` and a separate label be used for this.

The key point I want to make is that something that is semantically and syntactically external to the language should enter through a well regulated gateway. That gateway should be marked in some fashion that contextualizes its use and understanding to the foreign source so it's immediately understood to be non-native. It doesn't have to be part of `@objc` but things that aren't Swift native should never have a first class presence in the language. The approach to supporting one non-native language should be extensible to supporting other non-native languages.

-- E

···

On Apr 25, 2016, at 10:49 AM, Douglas Gregor <dgregor@apple.com> wrote:


(Charles Srstka) #17

The trouble with this is that it can be quite non-obvious whether a method in a protocol is required or not. If you have this:

protocol Foo {
    func bar()
    func baz ()
}

extension Foo {
    func bar() {}
}

it will generate this interface:

internal protocol Foo {
    internal func bar()
    internal func baz()
}

extension Foo {
    internal func bar()
}

There’s no way to tell which method you actually have to implement, simply from looking at the protocol. When there are only two methods, this isn’t hard to figure out, but what if there are 25 methods, each with extensive header docs in front of the declaration, and only two of them are required? The only way to find the required ones would be to first completely search through the entire library and/or framework for extensions on this type. Then, you'd look at the first method in the protocol, scroll down to the extension, scour the extension for that method name, then scour any *other* extensions you’ve found for the method name, then scroll back up to the protocol, look at the next method. Now, repeat the whole thing until you’ve done it 25 times, and hope you haven’t failed to spot a method name in an extension somewhere.

The upshot of all this is that it’s pretty easy to accidentally implement a method on a protocol because you thought you had to, when actually you didn’t. Requiring “override” would at least prevent that, although IMO it would be best if there were some kind of annotation on the protocol’s interface letting you know if there were already a default implementation for that method, similar to Objective-C’s good old optional keyword.

Charles

···

On Apr 25, 2016, at 11:49 AM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

(Tangentially, why not introduce a required "override" keyword for conforming types that implement a version of a member introduced in protocol extensions? This would match the class approach and enhance safety and intent.)

This is a commonly-requested feature that I don’t think we need. The TL;DR version is that I feel like specifying the conformance explicitly (my type Foo conforms to protocol P) already expresses intent, and the compiler should help with the rest. I’ve recently been working on providing better warnings for cases where one has tried to implement an optional requirement for a protocol (but got the declaration wrong), and I think we can turn it on for cases where one got a default implementation instead:


(Douglas Gregor) #18

* Swift already has an `Optional` type. Importing ObjC "optional" protocol requirements is therefore semantically problematic from a Swift development POV. I don't like either the "@objcoptional" or "@objc optional" solutions mentioned upthread. They overload "optional" syntactically and confuse semantics. I think the key words that better describe what's happening in, for example, a `UITableViewDelegate`, are "discretionary" or "elective" implementations. Swift has renamed lots of Objective C things (waves hi to SE-0005 <https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md>). Why not "optional”?

If we were adding optional requirements to Swift protocols, I would agree that it makes sense to change the nomenclature to avoid the oxymoron and the confusion with optionals. However, since this is now moving into the realm of “Objective-C compatibility feature”, I think it’s reasonable to retain the existing, Objective-C terminology.

Also, there is a link between the Optional type and optional requirements: when you reference an optional requirement, you get back an Optional.

Fair enough point but one that doesn't really sway me enough to include a native keyword for an ObjC compatibility feature.

It’s a contextual keyword, so the impact is far less than a full-fledged keyword (but, point taken).

Therefore I find it insufficient to introduce attributes like `@elective` or `@discretionary` in order to satisfy non-native requirements. I would prefer to see the @objc attribute be extended to support these and any future Objective-C-specific behaviors: @objc(elective), @objc(importedProtocolSupport: elective), or whatever. While these are wordy, I assume like any other Swift attributes they can be placed on a line before the function declaration, and it would be instantly clear why they've been placed there, and they would not overlap with Swift semantics *or* expectations. I leave the color of the bikeshed as an exercise for the reader.

Do remember that @objc(something) already has a meaning: it gives the Objective-C name “something” to the entity that the @objc(something) describes.

And this is something I *did* overlook. Is there leeway to add labeled items `@objc(x: y)`? If so, `@objc(something)` could transition to `@objc(somelabel: something)` and a separate label be used for this.

@objc(x: y) looks suspiciously like a typo for the selector @objc(x:y:).

The key point I want to make is that something that is semantically and syntactically external to the language should enter through a well regulated gateway.

It’s not semantically and syntactically external. It is a real feature with specific, unique type-checking behavior. It is externally-motivated, and limited to interoperability with another language, but that doesn’t make it an external feature in the way that (say) some other tool that generates Swift code is external.

  - Doug

···

On Apr 25, 2016, at 10:13 AM, Erica Sadun <erica@ericasadun.com> wrote:

On Apr 25, 2016, at 10:49 AM, Douglas Gregor <dgregor@apple.com <mailto:dgregor@apple.com>> wrote:


(Erica Sadun) #19

* Swift already has an `Optional` type. Importing ObjC "optional" protocol requirements is therefore semantically problematic from a Swift development POV. I don't like either the "@objcoptional" or "@objc optional" solutions mentioned upthread. They overload "optional" syntactically and confuse semantics. I think the key words that better describe what's happening in, for example, a `UITableViewDelegate`, are "discretionary" or "elective" implementations. Swift has renamed lots of Objective C things (waves hi to SE-0005 <https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md>). Why not "optional”?

If we were adding optional requirements to Swift protocols, I would agree that it makes sense to change the nomenclature to avoid the oxymoron and the confusion with optionals. However, since this is now moving into the realm of “Objective-C compatibility feature”, I think it’s reasonable to retain the existing, Objective-C terminology.

Also, there is a link between the Optional type and optional requirements: when you reference an optional requirement, you get back an Optional.

Fair enough point but one that doesn't really sway me enough to include a native keyword for an ObjC compatibility feature.

It’s a contextual keyword, so the impact is far less than a full-fledged keyword (but, point taken).

Ah, right.

Therefore I find it insufficient to introduce attributes like `@elective` or `@discretionary` in order to satisfy non-native requirements. I would prefer to see the @objc attribute be extended to support these and any future Objective-C-specific behaviors: @objc(elective), @objc(importedProtocolSupport: elective), or whatever. While these are wordy, I assume like any other Swift attributes they can be placed on a line before the function declaration, and it would be instantly clear why they've been placed there, and they would not overlap with Swift semantics *or* expectations. I leave the color of the bikeshed as an exercise for the reader.

Do remember that @objc(something) already has a meaning: it gives the Objective-C name “something” to the entity that the @objc(something) describes.

And this is something I *did* overlook. Is there leeway to add labeled items `@objc(x: y)`? If so, `@objc(something)` could transition to `@objc(somelabel: something)` and a separate label be used for this.

@objc(x: y) looks suspiciously like a typo for the selector @objc(x:y:).

Oh lord yes. Yes, it does. *headdesk*.

The key point I want to make is that something that is semantically and syntactically external to the language should enter through a well regulated gateway.

It’s not semantically and syntactically external. It is a real feature with specific, unique type-checking behavior. It is externally-motivated, and limited to interoperability with another language, but that doesn’t make it an external feature in the way that (say) some other tool that generates Swift code is external.

I think I made my points at least in terms of objc optional requirements though:

1. I think it's a very good thing.
2. I wish there were a better way to express it.

-- E, cc'ing in Chris who I believe *is* the review manager for SE-0070

···

On Apr 25, 2016, at 11:49 AM, Douglas Gregor <dgregor@apple.com> wrote:

On Apr 25, 2016, at 10:13 AM, Erica Sadun <erica@ericasadun.com <mailto:erica@ericasadun.com>> wrote:

On Apr 25, 2016, at 10:49 AM, Douglas Gregor <dgregor@apple.com <mailto:dgregor@apple.com>> wrote:


(Daniel Steinberg) #20

I am very glad to see that Swift protocols will not support optional requirements.

I wonder, however, if @objc is the wrong label. The requirement is less because of Objective-C and more because of Cocoa/Cocoa Touch APIs. I wonder if it’s useful to separate which things are being implemented because of differences between Swift and Objective-C and which things are being implemented for compatibility with Cocoa APIs which happen to be written in Objective-C.

A second example might be IBOutlets which are vars and have types such as UILabel! because of how storyboards and nibs come to life. Perhaps an @cocoa decoration there might allow them to be let and type UILabel to imply that they should be initialized once and before they are used - a runtime crash at development time in the case of an unconnected outlet would be expected.

In any case, I am generally for the proposal but wondering if an @cocoa tag might be more descriptive than @objc.

Best,

Daniel

···

On Apr 25, 2016, at 7:13 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 25, 2016, at 10:49 AM, Douglas Gregor <dgregor@apple.com <mailto:dgregor@apple.com>> wrote:

* Swift already has an `Optional` type. Importing ObjC "optional" protocol requirements is therefore semantically problematic from a Swift development POV. I don't like either the "@objcoptional" or "@objc optional" solutions mentioned upthread. They overload "optional" syntactically and confuse semantics. I think the key words that better describe what's happening in, for example, a `UITableViewDelegate`, are "discretionary" or "elective" implementations. Swift has renamed lots of Objective C things (waves hi to SE-0005 <https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md>). Why not "optional”?

If we were adding optional requirements to Swift protocols, I would agree that it makes sense to change the nomenclature to avoid the oxymoron and the confusion with optionals. However, since this is now moving into the realm of “Objective-C compatibility feature”, I think it’s reasonable to retain the existing, Objective-C terminology.

Also, there is a link between the Optional type and optional requirements: when you reference an optional requirement, you get back an Optional.

Fair enough point but one that doesn't really sway me enough to include a native keyword for an ObjC compatibility feature.

* I do *support* retaining `@objc` in some form and I believe it can be addressed in a way that does not appear to be a bug. "Optional protocol conformance" is a behavior that is external to the language. I do not believe would be voluntarily added to Swift should the topic arise.

It’s a feature that exists to support compatibility with another language; we would not add it if it not for Objective-C. However, it is a real language feature with different semantics from other language features.

Sounds like we're agreed on this point.

Therefore I find it insufficient to introduce attributes like `@elective` or `@discretionary` in order to satisfy non-native requirements. I would prefer to see the @objc attribute be extended to support these and any future Objective-C-specific behaviors: @objc(elective), @objc(importedProtocolSupport: elective), or whatever. While these are wordy, I assume like any other Swift attributes they can be placed on a line before the function declaration, and it would be instantly clear why they've been placed there, and they would not overlap with Swift semantics *or* expectations. I leave the color of the bikeshed as an exercise for the reader.

Do remember that @objc(something) already has a meaning: it gives the Objective-C name “something” to the entity that the @objc(something) describes.

And this is something I *did* overlook. Is there leeway to add labeled items `@objc(x: y)`? If so, `@objc(something)` could transition to `@objc(somelabel: something)` and a separate label be used for this.

The key point I want to make is that something that is semantically and syntactically external to the language should enter through a well regulated gateway. That gateway should be marked in some fashion that contextualizes its use and understanding to the foreign source so it's immediately understood to be non-native. It doesn't have to be part of `@objc` but things that aren't Swift native should never have a first class presence in the language. The approach to supporting one non-native language should be extensible to supporting other non-native languages.

-- E

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution