[Proposal draft] Referencing the Objective-C selector of a method


(Douglas Gregor) #1

Here’s a follow-up to the idea I posted for a simple expression to produce the selector for a given method, revised based on the discussion there. The proposal is over at

  https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md

Referencing the Objective-C selector of a method

Proposal: SE-NNNN <https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-objc-selectors.md>
Author(s): Doug Gregor <https://github.com/DougGregor>
Status: Awaiting review
Review manager: TBD
<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#introduction>Introduction

In Swift 2, Objective-C selectors are written as string literals (e.g., "insertSubview:aboveSubview:") in the type context of a Selector. This proposal seeks to replace this error-prone approach with Selector initialization syntax that refers to a specific method via its Swift name.

Swift-evolution thread: here <http://thread.gmane.org/gmane.comp.lang.swift.evolution/1384/focus=1403>
<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#motivation>Motivation

The use of string literals for selector names is extremely error-prone: there is no checking that the string is even a well-formed selector, much less that it refers to any known method, or a method of the intended class. Moreover, with the effort to perform automatic renaming of Objective-C APIs <https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md>, the link between Swift name and Objective-C selector is non-obvious. By providing explicit "create a selector" syntax based on the Swift name of a method, we eliminate the need for developers to reason about the actual Objective-C selectors being used.

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#proposed-solution>Proposed solution

Introduce Selector initialization syntax that allows one to build a selector from a reference to a method, e.g.,

control.sendAction(Selector(MyApplication.doSomething), to: target, forEvent: event)
where “doSomething” is a method of MyApplication, which might even have a completely-unrelated name in Objective-C:

extension MyApplication {
  @objc(jumpUpAndDown:)
  func doSomething(sender: AnyObject?) { … }
}
By naming the Swift method and having the Selector initializer do the work to form the Objective-C selector, we free the developer from having to do the naming translation manually and get static checking that the method exists and is exposed to Objective-C.

This proposal composes with the Naming Functions with Argument Labels proposal <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160111/006262.html>, which lets us name methods along with their argument labels, e.g.:

let sel = Selector(UIView.insertSubview(_:at:)) // produces the Selector "insertSubview:atIndex:"
With the introduction of the Selector syntax, we should deprecate the use of string literals to form selectors. Ideally, we could perform the deprecation in Swift 2.2 and remove the syntax entirely from Swift 3.

Additionally, we should introduce specific migrator support to translate string-literals-as-selectors into method references. Doing this well is non-trivial, requiring the compiler/migrator to find all of the declarations with a particular Objective-C selector and determine which one to reference. However, it should be feasible, and we can migrator other references to a specific, string-based initialization syntax (e.g., Selector("insertSubview:atIndex:")).

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#detailed-design>Detailed design

The proposed Selector initializer "almost" has the signature:

extension Selector {
  init<T, U>(_ fn: (T) -> U)
}
with some additional semantic restrictions that require that input be a reference to an objc method. Specifically, the input expression must be a direct reference to an Objective-C method, possibly parenthesized and possible with an "as" cast (which can be used to disambiguate same-named Swift methods). For example, here is a "highly general" example:

let sel = Selector(((UIKit.UIView.insertSubview(_:at:)) as (UIView) -> (UIView, Int) -> Void))
The actual implementation will introduce some magic in the type checker to only support references to methods within the Selector initialization syntax.

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#impact-on-existing-code>Impact on existing code

The introduction of the Selector initialization syntax has no impact on existing code. However, deprecating and removing the string-literal-as-selector syntax is a source-breaking change. We can migrate the uses to either the new Selectorinitialization syntax or to explicit initialization of a Selector from a string.

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

The primary alternative is type-safe selectors <https://lists.swift.org/pipermail/swift-evolution/2015-December/000233.html>, which would introduce a new "selector" calling convetion to capture the type of an @objc method, including its selector. One major benefit of type-safe selectors is that they can carry type information, improving type safety. From that discussion, referencing MyClass.observeNotification would produce a value of type:

@convention(selector) (MyClass) -> (NSNotification) -> Void
Objective-C APIs that accept selectors could provide type information (e.g., via Objective-C attributes or new syntax for a typed SEL), improving type safety for selector-based APIs. Personally, I feel that type-safe selectors are a well-designed feature that isn't worth doing: one would probably not use them outside of interoperability with existing Objective-C APIs, because closures are generally preferable (in both Swift and Objective-C). The cost of adding this feature to both Swift and Clang is significant, and we would also need adoption across a significant number of Objective-C APIs to make it worthwhile. On iOS, we are talking about a relatively small number of APIs (100-ish), and many of those have blocks/closure-based variants that are preferred anyway. Therefore, we should implement the simpler feature in this proposal rather than the far more complicated (but admittedly more type-safe) alternative approach.

  - Doug


(Tino) #2

+1
strings are error prone, and I'd expect the new syntax to support autocompletion.

As Joe has suggested in the "sister"-proposal, I think skipping the underscores makes sense.

Tino


(Wallacy) #3

Big +1

···

Em seg, 11 de jan de 2016 às 19:08, Douglas Gregor via swift-evolution < swift-evolution@swift.org> escreveu:

Here’s a follow-up to the idea I posted for a simple expression to produce
the selector for a given method, revised based on the discussion there. The
proposal is over at

https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md

Referencing the Objective-C selector of a method

   - Proposal: SE-NNNN
   <https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-objc-selectors.md>
   - Author(s): Doug Gregor <https://github.com/DougGregor>
   - Status: *Awaiting review*
   - Review manager: TBD

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#introduction>
Introduction

In Swift 2, Objective-C selectors are written as string literals (e.g.,
"insertSubview:aboveSubview:") in the type context of a Selector. This
proposal seeks to replace this error-prone approach with Selector initialization
syntax that refers to a specific method via its Swift name.

Swift-evolution thread: here
<http://thread.gmane.org/gmane.comp.lang.swift.evolution/1384/focus=1403>

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#motivation>
Motivation

The use of string literals for selector names is extremely error-prone:
there is no checking that the string is even a well-formed selector, much
less that it refers to any known method, or a method of the intended class.
Moreover, with the effort to perform automatic renaming of Objective-C
APIs
<https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md>,
the link between Swift name and Objective-C selector is non-obvious. By
providing explicit "create a selector" syntax based on the Swift name of a
method, we eliminate the need for developers to reason about the actual
Objective-C selectors being used.

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#proposed-solution>Proposed
solution

Introduce Selector initialization syntax that allows one to build a
selector from a reference to a method, e.g.,

control.sendAction(Selector(MyApplication.doSomething), to: target, forEvent: event)

where “doSomething” is a method of MyApplication, which might even have a
completely-unrelated name in Objective-C:

extension MyApplication {
  @objc(jumpUpAndDown:)
  func doSomething(sender: AnyObject?) { … }
}

By naming the Swift method and having the Selector initializer do the
work to form the Objective-C selector, we free the developer from having to
do the naming translation manually and get static checking that the method
exists and is exposed to Objective-C.

This proposal composes with the Naming Functions with Argument Labels
proposal
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160111/006262.html>,
which lets us name methods along with their argument labels, e.g.:

let sel = Selector(UIView.insertSubview(_:at:)) // produces the Selector "insertSubview:atIndex:"

With the introduction of the Selector syntax, we should deprecate the use
of string literals to form selectors. Ideally, we could perform the
deprecation in Swift 2.2 and remove the syntax entirely from Swift 3.

Additionally, we should introduce specific migrator support to translate
string-literals-as-selectors into method references. Doing this well is
non-trivial, requiring the compiler/migrator to find all of the
declarations with a particular Objective-C selector and determine which one
to reference. However, it should be feasible, and we can migrator other
references to a specific, string-based initialization syntax (e.g.,
Selector("insertSubview:atIndex:")).

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#detailed-design>Detailed
design

The proposed Selector initializer "almost" has the signature:

extension Selector {
  init<T, U>(_ fn: (T) -> U)
}

with some additional semantic restrictions that require that input be a
reference to an objc method. Specifically, the input expression must be a
direct reference to an Objective-C method, possibly parenthesized and
possible with an "as" cast (which can be used to disambiguate same-named
Swift methods). For example, here is a "highly general" example:

let sel = Selector(((UIKit.UIView.insertSubview(_:at:)) as (UIView) -> (UIView, Int) -> Void))

The actual implementation will introduce some magic in the type checker to
only support references to methods within the Selector initialization
syntax.

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#impact-on-existing-code>Impact
on existing code

The introduction of the Selector initialization syntax has no impact on
existing code. However, deprecating and removing the
string-literal-as-selector syntax is a source-breaking change. We can
migrate the uses to either the new Selectorinitialization syntax or to
explicit initialization of a Selector from a string.

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

The primary alternative is type-safe selectors
<https://lists.swift.org/pipermail/swift-evolution/2015-December/000233.html>,
which would introduce a new "selector" calling convetion to capture the
type of an @objc method, including its selector. One major benefit of
type-safe selectors is that they can carry type information, improving type
safety. From that discussion, referencing MyClass.observeNotification would
produce a value of type:

@convention(selector) (MyClass) -> (NSNotification) -> Void

Objective-C APIs that accept selectors could provide type information
(e.g., via Objective-C attributes or new syntax for a typed SEL),
improving type safety for selector-based APIs. Personally, I feel that
type-safe selectors are a well-designed feature that isn't worth doing: one
would probably not use them outside of interoperability with existing
Objective-C APIs, because closures are generally preferable (in both Swift
and Objective-C). The cost of adding this feature to both Swift and Clang
is significant, and we would also need adoption across a significant number
of Objective-C APIs to make it worthwhile. On iOS, we are talking about a
relatively small number of APIs (100-ish), and many of those have
blocks/closure-based variants that are preferred anyway. Therefore, we
should implement the simpler feature in this proposal rather than the far
more complicated (but admittedly more type-safe) alternative approach.

- Doug

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


(Brent Royal-Gordon) #4

control.sendAction(Selector(MyApplication.doSomething), to: target, forEvent: event)

How bad an idea would it be to make it simply be:

  control.sendAction(MyApplication.doSomething, to: target, forEvent: event)

That is, implicitly convert eligible unbound method references to selectors? From what I can tell, there's already going to be a certain amount of magic involved in this Selector initializer.

···

--
Brent Royal-Gordon
Architechies


(Andrew Bennett) #5

Sounds good to me, much nicer than the current approach.

Perhaps it should be @selector() instead? I don't think you can currently
get enough information from the type signature alone to differentiate one
selector from another. This will probably have to introduce new syntax, it
would require changes to the language not just a standard library function.
@selector seems to differentiate it from standard structures and functions.

I also think the underscore should be removed, that's outside the scope of
this proposal though?

I had concerns for this with Self and associated type requirements, however
I don't think they're an issue unless Objective-C supports them, or this is
to be used outside of Objective-C. For the same reasons I'm guessing
there's no need for this to distinguish between selectors with different
return types?

···

On Tue, Jan 12, 2016 at 8:08 AM, Douglas Gregor via swift-evolution < swift-evolution@swift.org> wrote:

Here’s a follow-up to the idea I posted for a simple expression to produce
the selector for a given method, revised based on the discussion there. The
proposal is over at

https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md

Referencing the Objective-C selector of a method

   - Proposal: SE-NNNN
   <https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-objc-selectors.md>
   - Author(s): Doug Gregor <https://github.com/DougGregor>
   - Status: *Awaiting review*
   - Review manager: TBD

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#introduction>
Introduction

In Swift 2, Objective-C selectors are written as string literals (e.g.,
"insertSubview:aboveSubview:") in the type context of a Selector. This
proposal seeks to replace this error-prone approach with Selector initialization
syntax that refers to a specific method via its Swift name.

Swift-evolution thread: here
<http://thread.gmane.org/gmane.comp.lang.swift.evolution/1384/focus=1403>

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#motivation>
Motivation

The use of string literals for selector names is extremely error-prone:
there is no checking that the string is even a well-formed selector, much
less that it refers to any known method, or a method of the intended class.
Moreover, with the effort to perform automatic renaming of Objective-C
APIs
<https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md>,
the link between Swift name and Objective-C selector is non-obvious. By
providing explicit "create a selector" syntax based on the Swift name of a
method, we eliminate the need for developers to reason about the actual
Objective-C selectors being used.

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#proposed-solution>Proposed
solution

Introduce Selector initialization syntax that allows one to build a
selector from a reference to a method, e.g.,

control.sendAction(Selector(MyApplication.doSomething), to: target, forEvent: event)

where “doSomething” is a method of MyApplication, which might even have a
completely-unrelated name in Objective-C:

extension MyApplication {
  @objc(jumpUpAndDown:)
  func doSomething(sender: AnyObject?) { … }
}

By naming the Swift method and having the Selector initializer do the
work to form the Objective-C selector, we free the developer from having to
do the naming translation manually and get static checking that the method
exists and is exposed to Objective-C.

This proposal composes with the Naming Functions with Argument Labels
proposal
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160111/006262.html>,
which lets us name methods along with their argument labels, e.g.:

let sel = Selector(UIView.insertSubview(_:at:)) // produces the Selector "insertSubview:atIndex:"

With the introduction of the Selector syntax, we should deprecate the use
of string literals to form selectors. Ideally, we could perform the
deprecation in Swift 2.2 and remove the syntax entirely from Swift 3.

Additionally, we should introduce specific migrator support to translate
string-literals-as-selectors into method references. Doing this well is
non-trivial, requiring the compiler/migrator to find all of the
declarations with a particular Objective-C selector and determine which one
to reference. However, it should be feasible, and we can migrator other
references to a specific, string-based initialization syntax (e.g.,
Selector("insertSubview:atIndex:")).

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#detailed-design>Detailed
design

The proposed Selector initializer "almost" has the signature:

extension Selector {
  init<T, U>(_ fn: (T) -> U)
}

with some additional semantic restrictions that require that input be a
reference to an objc method. Specifically, the input expression must be a
direct reference to an Objective-C method, possibly parenthesized and
possible with an "as" cast (which can be used to disambiguate same-named
Swift methods). For example, here is a "highly general" example:

let sel = Selector(((UIKit.UIView.insertSubview(_:at:)) as (UIView) -> (UIView, Int) -> Void))

The actual implementation will introduce some magic in the type checker to
only support references to methods within the Selector initialization
syntax.

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#impact-on-existing-code>Impact
on existing code

The introduction of the Selector initialization syntax has no impact on
existing code. However, deprecating and removing the
string-literal-as-selector syntax is a source-breaking change. We can
migrate the uses to either the new Selectorinitialization syntax or to
explicit initialization of a Selector from a string.

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

The primary alternative is type-safe selectors
<https://lists.swift.org/pipermail/swift-evolution/2015-December/000233.html>,
which would introduce a new "selector" calling convetion to capture the
type of an @objc method, including its selector. One major benefit of
type-safe selectors is that they can carry type information, improving type
safety. From that discussion, referencing MyClass.observeNotification would
produce a value of type:

@convention(selector) (MyClass) -> (NSNotification) -> Void

Objective-C APIs that accept selectors could provide type information
(e.g., via Objective-C attributes or new syntax for a typed SEL),
improving type safety for selector-based APIs. Personally, I feel that
type-safe selectors are a well-designed feature that isn't worth doing: one
would probably not use them outside of interoperability with existing
Objective-C APIs, because closures are generally preferable (in both Swift
and Objective-C). The cost of adding this feature to both Swift and Clang
is significant, and we would also need adoption across a significant number
of Objective-C APIs to make it worthwhile. On iOS, we are talking about a
relatively small number of APIs (100-ish), and many of those have
blocks/closure-based variants that are preferred anyway. Therefore, we
should implement the simpler feature in this proposal rather than the far
more complicated (but admittedly more type-safe) alternative approach.

- Doug

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


(David Hart) #6

Would this proposal allow Selector to be CustomStringConvertible? I often use @selector in my ORM classes and would like to be able to write:

class Person: ModelClass {
  var firstName: String = “”
  var lastName: String = “”

  func findPersonByName(name: String) -> Person? {
    db.firstObjectFromQuery(“SELECT * FROM \(self) WHERE \(Selector(Person.firstName)) = :name OR \(Selector(Person.lastName)) = :name”, args: [“name”: name])
  }
}

···

On 11 Jan 2016, at 22:08, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

Here’s a follow-up to the idea I posted for a simple expression to produce the selector for a given method, revised based on the discussion there. The proposal is over at

  https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md

Referencing the Objective-C selector of a method

Proposal: SE-NNNN <https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-objc-selectors.md>
Author(s): Doug Gregor <https://github.com/DougGregor>
Status: Awaiting review
Review manager: TBD
<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#introduction>Introduction

In Swift 2, Objective-C selectors are written as string literals (e.g., "insertSubview:aboveSubview:") in the type context of a Selector. This proposal seeks to replace this error-prone approach with Selector initialization syntax that refers to a specific method via its Swift name.

Swift-evolution thread: here <http://thread.gmane.org/gmane.comp.lang.swift.evolution/1384/focus=1403>
<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#motivation>Motivation

The use of string literals for selector names is extremely error-prone: there is no checking that the string is even a well-formed selector, much less that it refers to any known method, or a method of the intended class. Moreover, with the effort to perform automatic renaming of Objective-C APIs <https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md>, the link between Swift name and Objective-C selector is non-obvious. By providing explicit "create a selector" syntax based on the Swift name of a method, we eliminate the need for developers to reason about the actual Objective-C selectors being used.

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#proposed-solution>Proposed solution

Introduce Selector initialization syntax that allows one to build a selector from a reference to a method, e.g.,

control.sendAction(Selector(MyApplication.doSomething), to: target, forEvent: event)
where “doSomething” is a method of MyApplication, which might even have a completely-unrelated name in Objective-C:

extension MyApplication {
  @objc(jumpUpAndDown:)
  func doSomething(sender: AnyObject?) { … }
}
By naming the Swift method and having the Selector initializer do the work to form the Objective-C selector, we free the developer from having to do the naming translation manually and get static checking that the method exists and is exposed to Objective-C.

This proposal composes with the Naming Functions with Argument Labels proposal <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160111/006262.html>, which lets us name methods along with their argument labels, e.g.:

let sel = Selector(UIView.insertSubview(_:at:)) // produces the Selector "insertSubview:atIndex:"
With the introduction of the Selector syntax, we should deprecate the use of string literals to form selectors. Ideally, we could perform the deprecation in Swift 2.2 and remove the syntax entirely from Swift 3.

Additionally, we should introduce specific migrator support to translate string-literals-as-selectors into method references. Doing this well is non-trivial, requiring the compiler/migrator to find all of the declarations with a particular Objective-C selector and determine which one to reference. However, it should be feasible, and we can migrator other references to a specific, string-based initialization syntax (e.g., Selector("insertSubview:atIndex:")).

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#detailed-design>Detailed design

The proposed Selector initializer "almost" has the signature:

extension Selector {
  init<T, U>(_ fn: (T) -> U)
}
with some additional semantic restrictions that require that input be a reference to an objc method. Specifically, the input expression must be a direct reference to an Objective-C method, possibly parenthesized and possible with an "as" cast (which can be used to disambiguate same-named Swift methods). For example, here is a "highly general" example:

let sel = Selector(((UIKit.UIView.insertSubview(_:at:)) as (UIView) -> (UIView, Int) -> Void))
The actual implementation will introduce some magic in the type checker to only support references to methods within the Selector initialization syntax.

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#impact-on-existing-code>Impact on existing code

The introduction of the Selector initialization syntax has no impact on existing code. However, deprecating and removing the string-literal-as-selector syntax is a source-breaking change. We can migrate the uses to either the new Selectorinitialization syntax or to explicit initialization of a Selector from a string.

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

The primary alternative is type-safe selectors <https://lists.swift.org/pipermail/swift-evolution/2015-December/000233.html>, which would introduce a new "selector" calling convetion to capture the type of an @objc method, including its selector. One major benefit of type-safe selectors is that they can carry type information, improving type safety. From that discussion, referencing MyClass.observeNotification would produce a value of type:

@convention(selector) (MyClass) -> (NSNotification) -> Void
Objective-C APIs that accept selectors could provide type information (e.g., via Objective-C attributes or new syntax for a typed SEL), improving type safety for selector-based APIs. Personally, I feel that type-safe selectors are a well-designed feature that isn't worth doing: one would probably not use them outside of interoperability with existing Objective-C APIs, because closures are generally preferable (in both Swift and Objective-C). The cost of adding this feature to both Swift and Clang is significant, and we would also need adoption across a significant number of Objective-C APIs to make it worthwhile. On iOS, we are talking about a relatively small number of APIs (100-ish), and many of those have blocks/closure-based variants that are preferred anyway. Therefore, we should implement the simpler feature in this proposal rather than the far more complicated (but admittedly more type-safe) alternative approach.

  - Doug

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


(Douglas Gregor) #7

Sounds good to me, much nicer than the current approach.

Perhaps it should be @selector() instead? I don't think you can currently get enough information from the type signature alone to differentiate one selector from another. This will probably have to introduce new syntax, it would require changes to the language not just a standard library function. @selector seems to differentiate it from standard structures and functions.

@ is for attributes, so that doesn’t work. I’ll add commentary to the proposal, since this keeps coming up.

I also think the underscore should be removed, that's outside the scope of this proposal though?

I’m strongly opposed to doing it only for this syntax. Doing it globally is annoying, because it requires changes in Clang as well.

I had concerns for this with Self and associated type requirements, however I don't think they're an issue unless Objective-C supports them, or this is to be used outside of Objective-C.

I don’t see this as being a problem now or in the future.

For the same reasons I'm guessing there's no need for this to distinguish between selectors with different return types?

One can introduce type context (with “as”) if this actually comes up. It should be *extremely* rare with Objective-C methods.

  - Doug

···

On Jan 11, 2016, at 1:58 PM, Andrew Bennett <cacoyi@gmail.com> wrote:

On Tue, Jan 12, 2016 at 8:08 AM, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Here’s a follow-up to the idea I posted for a simple expression to produce the selector for a given method, revised based on the discussion there. The proposal is over at

  https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md

Referencing the Objective-C selector of a method

Proposal: SE-NNNN <https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-objc-selectors.md>
Author(s): Doug Gregor <https://github.com/DougGregor>
Status: Awaiting review
Review manager: TBD
<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#introduction>Introduction

In Swift 2, Objective-C selectors are written as string literals (e.g., "insertSubview:aboveSubview:") in the type context of a Selector. This proposal seeks to replace this error-prone approach with Selector initialization syntax that refers to a specific method via its Swift name.

Swift-evolution thread: here <http://thread.gmane.org/gmane.comp.lang.swift.evolution/1384/focus=1403>
<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#motivation>Motivation

The use of string literals for selector names is extremely error-prone: there is no checking that the string is even a well-formed selector, much less that it refers to any known method, or a method of the intended class. Moreover, with the effort to perform automatic renaming of Objective-C APIs <https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md>, the link between Swift name and Objective-C selector is non-obvious. By providing explicit "create a selector" syntax based on the Swift name of a method, we eliminate the need for developers to reason about the actual Objective-C selectors being used.

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#proposed-solution>Proposed solution

Introduce Selector initialization syntax that allows one to build a selector from a reference to a method, e.g.,

control.sendAction(Selector(MyApplication.doSomething), to: target, forEvent: event)
where “doSomething” is a method of MyApplication, which might even have a completely-unrelated name in Objective-C:

extension MyApplication {
  @objc(jumpUpAndDown:)
  func doSomething(sender: AnyObject?) { … }
}
By naming the Swift method and having the Selector initializer do the work to form the Objective-C selector, we free the developer from having to do the naming translation manually and get static checking that the method exists and is exposed to Objective-C.

This proposal composes with the Naming Functions with Argument Labels proposal <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160111/006262.html>, which lets us name methods along with their argument labels, e.g.:

let sel = Selector(UIView.insertSubview(_:at:)) // produces the Selector "insertSubview:atIndex:"
With the introduction of the Selector syntax, we should deprecate the use of string literals to form selectors. Ideally, we could perform the deprecation in Swift 2.2 and remove the syntax entirely from Swift 3.

Additionally, we should introduce specific migrator support to translate string-literals-as-selectors into method references. Doing this well is non-trivial, requiring the compiler/migrator to find all of the declarations with a particular Objective-C selector and determine which one to reference. However, it should be feasible, and we can migrator other references to a specific, string-based initialization syntax (e.g., Selector("insertSubview:atIndex:")).

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#detailed-design>Detailed design

The proposed Selector initializer "almost" has the signature:

extension Selector {
  init<T, U>(_ fn: (T) -> U)
}
with some additional semantic restrictions that require that input be a reference to an objc method. Specifically, the input expression must be a direct reference to an Objective-C method, possibly parenthesized and possible with an "as" cast (which can be used to disambiguate same-named Swift methods). For example, here is a "highly general" example:

let sel = Selector(((UIKit.UIView.insertSubview(_:at:)) as (UIView) -> (UIView, Int) -> Void))
The actual implementation will introduce some magic in the type checker to only support references to methods within the Selector initialization syntax.

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#impact-on-existing-code>Impact on existing code

The introduction of the Selector initialization syntax has no impact on existing code. However, deprecating and removing the string-literal-as-selector syntax is a source-breaking change. We can migrate the uses to either the new Selectorinitialization syntax or to explicit initialization of a Selector from a string.

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

The primary alternative is type-safe selectors <https://lists.swift.org/pipermail/swift-evolution/2015-December/000233.html>, which would introduce a new "selector" calling convetion to capture the type of an @objc method, including its selector. One major benefit of type-safe selectors is that they can carry type information, improving type safety. From that discussion, referencing MyClass.observeNotification would produce a value of type:

@convention(selector) (MyClass) -> (NSNotification) -> Void
Objective-C APIs that accept selectors could provide type information (e.g., via Objective-C attributes or new syntax for a typed SEL), improving type safety for selector-based APIs. Personally, I feel that type-safe selectors are a well-designed feature that isn't worth doing: one would probably not use them outside of interoperability with existing Objective-C APIs, because closures are generally preferable (in both Swift and Objective-C). The cost of adding this feature to both Swift and Clang is significant, and we would also need adoption across a significant number of Objective-C APIs to make it worthwhile. On iOS, we are talking about a relatively small number of APIs (100-ish), and many of those have blocks/closure-based variants that are preferred anyway. Therefore, we should implement the simpler feature in this proposal rather than the far more complicated (but admittedly more type-safe) alternative approach.

  - Doug

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


(Félix Cloutier) #8

The underscore is discussed in "[swift-evolution] [Proposal draft #2] Naming Functions with Argument Labels".

Selectors carry no type information at all. They don't belong to a class, they don't indicate their return value (if any), they don't indicate their parameter types.

Félix

···

Le 11 janv. 2016 à 16:58:17, Andrew Bennett via swift-evolution <swift-evolution@swift.org> a écrit :

Sounds good to me, much nicer than the current approach.

Perhaps it should be @selector() instead? I don't think you can currently get enough information from the type signature alone to differentiate one selector from another. This will probably have to introduce new syntax, it would require changes to the language not just a standard library function. @selector seems to differentiate it from standard structures and functions.

I also think the underscore should be removed, that's outside the scope of this proposal though?

I had concerns for this with Self and associated type requirements, however I don't think they're an issue unless Objective-C supports them, or this is to be used outside of Objective-C. For the same reasons I'm guessing there's no need for this to distinguish between selectors with different return types?

On Tue, Jan 12, 2016 at 8:08 AM, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Here’s a follow-up to the idea I posted for a simple expression to produce the selector for a given method, revised based on the discussion there. The proposal is over at

  https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md

Referencing the Objective-C selector of a method

Proposal: SE-NNNN <https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-objc-selectors.md>
Author(s): Doug Gregor <https://github.com/DougGregor>
Status: Awaiting review
Review manager: TBD
<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#introduction>Introduction

In Swift 2, Objective-C selectors are written as string literals (e.g., "insertSubview:aboveSubview:") in the type context of a Selector. This proposal seeks to replace this error-prone approach with Selector initialization syntax that refers to a specific method via its Swift name.

Swift-evolution thread: here <http://thread.gmane.org/gmane.comp.lang.swift.evolution/1384/focus=1403>
<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#motivation>Motivation

The use of string literals for selector names is extremely error-prone: there is no checking that the string is even a well-formed selector, much less that it refers to any known method, or a method of the intended class. Moreover, with the effort to perform automatic renaming of Objective-C APIs <https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md>, the link between Swift name and Objective-C selector is non-obvious. By providing explicit "create a selector" syntax based on the Swift name of a method, we eliminate the need for developers to reason about the actual Objective-C selectors being used.

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#proposed-solution>Proposed solution

Introduce Selector initialization syntax that allows one to build a selector from a reference to a method, e.g.,

control.sendAction(Selector(MyApplication.doSomething), to: target, forEvent: event)
where “doSomething” is a method of MyApplication, which might even have a completely-unrelated name in Objective-C:

extension MyApplication {
  @objc(jumpUpAndDown:)
  func doSomething(sender: AnyObject?) { … }
}
By naming the Swift method and having the Selector initializer do the work to form the Objective-C selector, we free the developer from having to do the naming translation manually and get static checking that the method exists and is exposed to Objective-C.

This proposal composes with the Naming Functions with Argument Labels proposal <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160111/006262.html>, which lets us name methods along with their argument labels, e.g.:

let sel = Selector(UIView.insertSubview(_:at:)) // produces the Selector "insertSubview:atIndex:"
With the introduction of the Selector syntax, we should deprecate the use of string literals to form selectors. Ideally, we could perform the deprecation in Swift 2.2 and remove the syntax entirely from Swift 3.

Additionally, we should introduce specific migrator support to translate string-literals-as-selectors into method references. Doing this well is non-trivial, requiring the compiler/migrator to find all of the declarations with a particular Objective-C selector and determine which one to reference. However, it should be feasible, and we can migrator other references to a specific, string-based initialization syntax (e.g., Selector("insertSubview:atIndex:")).

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#detailed-design>Detailed design

The proposed Selector initializer "almost" has the signature:

extension Selector {
  init<T, U>(_ fn: (T) -> U)
}
with some additional semantic restrictions that require that input be a reference to an objc method. Specifically, the input expression must be a direct reference to an Objective-C method, possibly parenthesized and possible with an "as" cast (which can be used to disambiguate same-named Swift methods). For example, here is a "highly general" example:

let sel = Selector(((UIKit.UIView.insertSubview(_:at:)) as (UIView) -> (UIView, Int) -> Void))
The actual implementation will introduce some magic in the type checker to only support references to methods within the Selector initialization syntax.

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#impact-on-existing-code>Impact on existing code

The introduction of the Selector initialization syntax has no impact on existing code. However, deprecating and removing the string-literal-as-selector syntax is a source-breaking change. We can migrate the uses to either the new Selectorinitialization syntax or to explicit initialization of a Selector from a string.

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

The primary alternative is type-safe selectors <https://lists.swift.org/pipermail/swift-evolution/2015-December/000233.html>, which would introduce a new "selector" calling convetion to capture the type of an @objc method, including its selector. One major benefit of type-safe selectors is that they can carry type information, improving type safety. From that discussion, referencing MyClass.observeNotification would produce a value of type:

@convention(selector) (MyClass) -> (NSNotification) -> Void
Objective-C APIs that accept selectors could provide type information (e.g., via Objective-C attributes or new syntax for a typed SEL), improving type safety for selector-based APIs. Personally, I feel that type-safe selectors are a well-designed feature that isn't worth doing: one would probably not use them outside of interoperability with existing Objective-C APIs, because closures are generally preferable (in both Swift and Objective-C). The cost of adding this feature to both Swift and Clang is significant, and we would also need adoption across a significant number of Objective-C APIs to make it worthwhile. On iOS, we are talking about a relatively small number of APIs (100-ish), and many of those have blocks/closure-based variants that are preferred anyway. Therefore, we should implement the simpler feature in this proposal rather than the far more complicated (but admittedly more type-safe) alternative approach.

  - Doug

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

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


(Douglas Gregor) #9

I’m strongly against making this an implicit conversion. It’s a very lossy conversion, losing bother type information and (for something like myApplicationInstance.doSomething) the apparently-bound “self”. It should also not be super-common (so we don’t need to syntax-optimize it) and isn’t available where there is no Objective-C runtime.

  - Doug

···

On Jan 11, 2016, at 11:42 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

control.sendAction(Selector(MyApplication.doSomething), to: target, forEvent: event)

How bad an idea would it be to make it simply be:

  control.sendAction(MyApplication.doSomething, to: target, forEvent: event)

That is, implicitly convert eligible unbound method references to selectors? From what I can tell, there's already going to be a certain amount of magic involved in this Selector initializer.


(Douglas Gregor) #10

Would this proposal allow Selector to be CustomStringConvertible? I often use @selector in my ORM classes and would like to be able to write:

class Person: ModelClass {
  var firstName: String = “”
  var lastName: String = “”

  func findPersonByName(name: String) -> Person? {
    db.firstObjectFromQuery(“SELECT * FROM \(self) WHERE \(Selector(Person.firstName)) = :name OR \(Selector(Person.lastName)) = :name”, args: [“name”: name])
  }
}

It’s orthogonal to this proposal, but you’re absolutely right that Selector should be CustomStringConvertible.

  - Doug

···

On Jan 12, 2016, at 12:36 AM, David Hart <david@hartbit.com> wrote:

On 11 Jan 2016, at 22:08, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Here’s a follow-up to the idea I posted for a simple expression to produce the selector for a given method, revised based on the discussion there. The proposal is over at

  https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md

Referencing the Objective-C selector of a method

Proposal: SE-NNNN <https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-objc-selectors.md>
Author(s): Doug Gregor <https://github.com/DougGregor>
Status: Awaiting review
Review manager: TBD
<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#introduction>Introduction

In Swift 2, Objective-C selectors are written as string literals (e.g., "insertSubview:aboveSubview:") in the type context of a Selector. This proposal seeks to replace this error-prone approach with Selector initialization syntax that refers to a specific method via its Swift name.

Swift-evolution thread: here <http://thread.gmane.org/gmane.comp.lang.swift.evolution/1384/focus=1403>
<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#motivation>Motivation

The use of string literals for selector names is extremely error-prone: there is no checking that the string is even a well-formed selector, much less that it refers to any known method, or a method of the intended class. Moreover, with the effort to perform automatic renaming of Objective-C APIs <https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md>, the link between Swift name and Objective-C selector is non-obvious. By providing explicit "create a selector" syntax based on the Swift name of a method, we eliminate the need for developers to reason about the actual Objective-C selectors being used.

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#proposed-solution>Proposed solution

Introduce Selector initialization syntax that allows one to build a selector from a reference to a method, e.g.,

control.sendAction(Selector(MyApplication.doSomething), to: target, forEvent: event)
where “doSomething” is a method of MyApplication, which might even have a completely-unrelated name in Objective-C:

extension MyApplication {
  @objc(jumpUpAndDown:)
  func doSomething(sender: AnyObject?) { … }
}
By naming the Swift method and having the Selector initializer do the work to form the Objective-C selector, we free the developer from having to do the naming translation manually and get static checking that the method exists and is exposed to Objective-C.

This proposal composes with the Naming Functions with Argument Labels proposal <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160111/006262.html>, which lets us name methods along with their argument labels, e.g.:

let sel = Selector(UIView.insertSubview(_:at:)) // produces the Selector "insertSubview:atIndex:"
With the introduction of the Selector syntax, we should deprecate the use of string literals to form selectors. Ideally, we could perform the deprecation in Swift 2.2 and remove the syntax entirely from Swift 3.

Additionally, we should introduce specific migrator support to translate string-literals-as-selectors into method references. Doing this well is non-trivial, requiring the compiler/migrator to find all of the declarations with a particular Objective-C selector and determine which one to reference. However, it should be feasible, and we can migrator other references to a specific, string-based initialization syntax (e.g., Selector("insertSubview:atIndex:")).

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#detailed-design>Detailed design

The proposed Selector initializer "almost" has the signature:

extension Selector {
  init<T, U>(_ fn: (T) -> U)
}
with some additional semantic restrictions that require that input be a reference to an objc method. Specifically, the input expression must be a direct reference to an Objective-C method, possibly parenthesized and possible with an "as" cast (which can be used to disambiguate same-named Swift methods). For example, here is a "highly general" example:

let sel = Selector(((UIKit.UIView.insertSubview(_:at:)) as (UIView) -> (UIView, Int) -> Void))
The actual implementation will introduce some magic in the type checker to only support references to methods within the Selector initialization syntax.

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#impact-on-existing-code>Impact on existing code

The introduction of the Selector initialization syntax has no impact on existing code. However, deprecating and removing the string-literal-as-selector syntax is a source-breaking change. We can migrate the uses to either the new Selectorinitialization syntax or to explicit initialization of a Selector from a string.

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

The primary alternative is type-safe selectors <https://lists.swift.org/pipermail/swift-evolution/2015-December/000233.html>, which would introduce a new "selector" calling convetion to capture the type of an @objc method, including its selector. One major benefit of type-safe selectors is that they can carry type information, improving type safety. From that discussion, referencing MyClass.observeNotification would produce a value of type:

@convention(selector) (MyClass) -> (NSNotification) -> Void
Objective-C APIs that accept selectors could provide type information (e.g., via Objective-C attributes or new syntax for a typed SEL), improving type safety for selector-based APIs. Personally, I feel that type-safe selectors are a well-designed feature that isn't worth doing: one would probably not use them outside of interoperability with existing Objective-C APIs, because closures are generally preferable (in both Swift and Objective-C). The cost of adding this feature to both Swift and Clang is significant, and we would also need adoption across a significant number of Objective-C APIs to make it worthwhile. On iOS, we are talking about a relatively small number of APIs (100-ish), and many of those have blocks/closure-based variants that are preferred anyway. Therefore, we should implement the simpler feature in this proposal rather than the far more complicated (but admittedly more type-safe) alternative approach.

  - Doug

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


(Andrew Bennett) #11

I agree on pretty much every point. I also saw the light on _ since writing
that :slight_smile:

+1

···

On Tue, Jan 12, 2016 at 9:04 AM, Douglas Gregor <dgregor@apple.com> wrote:

On Jan 11, 2016, at 1:58 PM, Andrew Bennett <cacoyi@gmail.com> wrote:

Sounds good to me, much nicer than the current approach.

Perhaps it should be @selector() instead? I don't think you can currently
get enough information from the type signature alone to differentiate one
selector from another. This will probably have to introduce new syntax, it
would require changes to the language not just a standard library function.
@selector seems to differentiate it from standard structures and functions.

@ is for attributes, so that doesn’t work. I’ll add commentary to the
proposal, since this keeps coming up.

I also think the underscore should be removed, that's outside the scope of
this proposal though?

I’m strongly opposed to doing it only for this syntax. Doing it globally
is annoying, because it requires changes in Clang as well.

I had concerns for this with Self and associated type requirements,
however I don't think they're an issue unless Objective-C supports them, or
this is to be used outside of Objective-C.

I don’t see this as being a problem now or in the future.

For the same reasons I'm guessing there's no need for this to distinguish
between selectors with different return types?

One can introduce type context (with “as”) if this actually comes up. It
should be *extremely* rare with Objective-C methods.

- Doug

On Tue, Jan 12, 2016 at 8:08 AM, Douglas Gregor via swift-evolution < > swift-evolution@swift.org> wrote:

Here’s a follow-up to the idea I posted for a simple expression to
produce the selector for a given method, revised based on the discussion
there. The proposal is over at

https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md

Referencing the Objective-C selector of a method

   - Proposal: SE-NNNN
   <https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-objc-selectors.md>
   - Author(s): Doug Gregor <https://github.com/DougGregor>
   - Status: *Awaiting review*
   - Review manager: TBD

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#introduction>
Introduction

In Swift 2, Objective-C selectors are written as string literals (e.g.,
"insertSubview:aboveSubview:") in the type context of a Selector. This
proposal seeks to replace this error-prone approach with Selector initialization
syntax that refers to a specific method via its Swift name.

Swift-evolution thread: here
<http://thread.gmane.org/gmane.comp.lang.swift.evolution/1384/focus=1403>

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#motivation>
Motivation

The use of string literals for selector names is extremely error-prone:
there is no checking that the string is even a well-formed selector, much
less that it refers to any known method, or a method of the intended class.
Moreover, with the effort to perform automatic renaming of Objective-C
APIs
<https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md>,
the link between Swift name and Objective-C selector is non-obvious. By
providing explicit "create a selector" syntax based on the Swift name of a
method, we eliminate the need for developers to reason about the actual
Objective-C selectors being used.

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#proposed-solution>Proposed
solution

Introduce Selector initialization syntax that allows one to build a
selector from a reference to a method, e.g.,

control.sendAction(Selector(MyApplication.doSomething), to: target, forEvent: event)

where “doSomething” is a method of MyApplication, which might even have a
completely-unrelated name in Objective-C:

extension MyApplication {
  @objc(jumpUpAndDown:)
  func doSomething(sender: AnyObject?) { … }
}

By naming the Swift method and having the Selector initializer do the
work to form the Objective-C selector, we free the developer from having to
do the naming translation manually and get static checking that the method
exists and is exposed to Objective-C.

This proposal composes with the Naming Functions with Argument Labels
proposal
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160111/006262.html>,
which lets us name methods along with their argument labels, e.g.:

let sel = Selector(UIView.insertSubview(_:at:)) // produces the Selector "insertSubview:atIndex:"

With the introduction of the Selector syntax, we should deprecate the
use of string literals to form selectors. Ideally, we could perform the
deprecation in Swift 2.2 and remove the syntax entirely from Swift 3.

Additionally, we should introduce specific migrator support to translate
string-literals-as-selectors into method references. Doing this well is
non-trivial, requiring the compiler/migrator to find all of the
declarations with a particular Objective-C selector and determine which one
to reference. However, it should be feasible, and we can migrator other
references to a specific, string-based initialization syntax (e.g.,
Selector("insertSubview:atIndex:")).

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#detailed-design>Detailed
design

The proposed Selector initializer "almost" has the signature:

extension Selector {
  init<T, U>(_ fn: (T) -> U)
}

with some additional semantic restrictions that require that input be a
reference to an objc method. Specifically, the input expression must be
a direct reference to an Objective-C method, possibly parenthesized and
possible with an "as" cast (which can be used to disambiguate same-named
Swift methods). For example, here is a "highly general" example:

let sel = Selector(((UIKit.UIView.insertSubview(_:at:)) as (UIView) -> (UIView, Int) -> Void))

The actual implementation will introduce some magic in the type checker
to only support references to methods within the Selector initialization
syntax.

<https://github.com/DougGregor/swift-evolution/blob/objc-selectors/proposals/0000-objc-selectors.md#impact-on-existing-code>Impact
on existing code

The introduction of the Selector initialization syntax has no impact on
existing code. However, deprecating and removing the
string-literal-as-selector syntax is a source-breaking change. We can
migrate the uses to either the new Selectorinitialization syntax or to
explicit initialization of a Selector from a string.

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

The primary alternative is type-safe selectors
<https://lists.swift.org/pipermail/swift-evolution/2015-December/000233.html>,
which would introduce a new "selector" calling convetion to capture the
type of an @objc method, including its selector. One major benefit of
type-safe selectors is that they can carry type information, improving type
safety. From that discussion, referencing MyClass.observeNotification would
produce a value of type:

@convention(selector) (MyClass) -> (NSNotification) -> Void

Objective-C APIs that accept selectors could provide type information
(e.g., via Objective-C attributes or new syntax for a typed SEL),
improving type safety for selector-based APIs. Personally, I feel that
type-safe selectors are a well-designed feature that isn't worth doing: one
would probably not use them outside of interoperability with existing
Objective-C APIs, because closures are generally preferable (in both Swift
and Objective-C). The cost of adding this feature to both Swift and Clang
is significant, and we would also need adoption across a significant number
of Objective-C APIs to make it worthwhile. On iOS, we are talking about a
relatively small number of APIs (100-ish), and many of those have
blocks/closure-based variants that are preferred anyway. Therefore, we
should implement the simpler feature in this proposal rather than the far
more complicated (but admittedly more type-safe) alternative approach.

- Doug

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