Disallow arbitrary expressions in selectors


(Alex Hoppen) #1

During the implementation of SE-0064 (Referencing Objective-C selector of property getters and setters) I have come across an issue that could be resolved my a minor change to the language and simplify the compiler a lot. I have drafted a proposal below.

Thoughts, comments, especially objections, appreciated.

– Alex

GitHub-Link: https://github.com/ahoppen/swift-evolution/blob/arbitrary-expressions-in-selectors/proposals/0000-arbitrary-expressions-in-selectors.md

Disallow arbitrary expressions in selectors

Proposal: SE-NNNN <https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md>
Author(s): Alex Hoppen <https://github.com/ahoppen>
Status: Draft
Review manager: TBD
<https://github.com/ahoppen/swift-evolution/blob/arbitrary-expressions-in-selectors/proposals/0000-arbitrary-expressions-in-selectors.md#introduction>Introduction

It is currently possible to write arbitrary expressions inside #selector like the following: #selector(callThisFunc().bar). This complicates the implementation of proposals SE-0064 <https://github.com/apple/swift-evolution/blob/master/proposals/0064-property-selectors.md> (Referencing Objective-C selector of property getters and setters) and SE-0062 <https://github.com/apple/swift-evolution/blob/master/proposals/0062-objc-keypaths.md> (Referencing Objective-C key-paths) a lot.

This proposal restricts expressions inside selectors to be a sequence of property or method refernces. I believe this will not be a major restrictions since arbitrary expressions in selectors are probably rarely used, have some rough edges and removing them would simplify the compiler.

<https://github.com/ahoppen/swift-evolution/blob/arbitrary-expressions-in-selectors/proposals/0000-arbitrary-expressions-in-selectors.md#proposed-solution>Proposed solution

I propose allowed expressions inside #selector (and once implemented #keyPath) to be a series of instance or class members separated by . and allow disambiguating the last component using as.

<https://github.com/ahoppen/swift-evolution/blob/arbitrary-expressions-in-selectors/proposals/0000-arbitrary-expressions-in-selectors.md#detailed-design>Detailed design

<https://github.com/ahoppen/swift-evolution/blob/arbitrary-expressions-in-selectors/proposals/0000-arbitrary-expressions-in-selectors.md#examples>Examples

class Address: NSObject {
  dynamic var street: String
  dynamic var town: String

  init(street: String, town: String) {
    self.street = street
    self.town = town
  }
}

class Person: NSObject {
  dynamic var name: String
  dynamic var homeAddress: Address

  func workAddress() -> Address {
    // ...
  }

  func workAddress(formatter: AddressFormatter) -> String {
    // ...
  }

  init(name: String, homeAddress: Address) {
    self.name = name
    self.homeAddress = homeAddress
  }
}

let me: Person = ...
The following examples will continue to work:

let _ = #selector(getter: Person.name)
let _ = #selector(getter: me.name)

let _ = #selector(getter: Person.homeAddress.street)
// Could also be written as
let _ = #selector(getter: Address.street)

let _ = #selector(Person.workAddress as () -> Address)
let _ = #selector(Person.workAddress(formatter: ))
I propose removing this kind of selector:

// Should produce selector "street". Note that the method workAddress() is never
// called and its return type only used during type checking
let _ = #selector(getter: me.workAddress().street)

// The above can be rewritten in a cleaner way like the following
let _ = #selector(getter: Address.street)
The proposed way to rewrite the selector elimininates potential confusion about the fact that calling a method inside #selector actually doesn't invoke it.

<https://github.com/ahoppen/swift-evolution/blob/arbitrary-expressions-in-selectors/proposals/0000-arbitrary-expressions-in-selectors.md#grammar>Grammar

selector → #selector(selector-modiferopt selector-path)

selector-modifier → getter:
selector-modifier → setter:

selector-path → type-identifier . selector-member-path as-disambiguationopt
selector-path → selector-member-path as-disambiguationopt

selector-member-path → identifier
selector-member-path → unqualified-name
selector-member-path → identifier . selector-member-path

as-disambiguation → as type-identifier
For a further rationale on why arbitrary expressions are no longer possible, see the discussion <https://bugs.swift.org/browse/SR-1239?focusedCommentId=13958&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-13958> on bugs.swift.org.

<https://github.com/ahoppen/swift-evolution/blob/arbitrary-expressions-in-selectors/proposals/0000-arbitrary-expressions-in-selectors.md#impact-on-existing-code>Impact on existing code

Code that currently uses this feature needs to be rewritten as described in the example above. I believe, however, that the feature is rarely used so it will affect only very little source code and where it is currently used the proposed update is actually more readable.

<https://github.com/ahoppen/swift-evolution/blob/arbitrary-expressions-in-selectors/proposals/0000-arbitrary-expressions-in-selectors.md#alternatives-considered>Alternatives considered

The only alternative I see is trying to keep the current semantics and implement them for the getter:/setter: selectors.


(Thorsten Seitz) #2

Looks good to me!

-Thorsten

···

Am 28.04.2016 um 16:56 schrieb Alex Hoppen via swift-evolution <swift-evolution@swift.org>:

During the implementation of SE-0064 (Referencing Objective-C selector of property getters and setters) I have come across an issue that could be resolved my a minor change to the language and simplify the compiler a lot. I have drafted a proposal below.

Thoughts, comments, especially objections, appreciated.

– Alex

GitHub-Link: https://github.com/ahoppen/swift-evolution/blob/arbitrary-expressions-in-selectors/proposals/0000-arbitrary-expressions-in-selectors.md

Disallow arbitrary expressions in selectors
Proposal: SE-NNNN
Author(s): Alex Hoppen
Status: Draft
Review manager: TBD
Introduction

It is currently possible to write arbitrary expressions inside #selector like the following: #selector(callThisFunc().bar). This complicates the implementation of proposals SE-0064 (Referencing Objective-C selector of property getters and setters) and SE-0062 (Referencing Objective-C key-paths) a lot.

This proposal restricts expressions inside selectors to be a sequence of property or method refernces. I believe this will not be a major restrictions since arbitrary expressions in selectors are probably rarely used, have some rough edges and removing them would simplify the compiler.

Proposed solution

I propose allowed expressions inside #selector (and once implemented #keyPath) to be a series of instance or class members separated by . and allow disambiguating the last component using as.

Detailed design

Examples

class Address: NSObject {
  dynamic var street: String
  dynamic var town: String

  init(street: String, town: String) {
    self.street = street
    self.town = town
  }
}

class Person: NSObject {
  dynamic var name: String
  dynamic var homeAddress: Address

  func workAddress() -> Address {
    // ...
  }

  func workAddress(formatter: AddressFormatter) -> String {
    // ...
  }

  init(name: String, homeAddress: Address) {
    self.name = name
    self.homeAddress = homeAddress
  }
}

let me: Person = ...
The following examples will continue to work:

let _ = #selector(getter: Person.name)
let _ = #selector(getter: me.name)

let _ = #selector(getter: Person.homeAddress.street)
// Could also be written as
let _ = #selector(getter: Address.street)

let _ = #selector(Person.workAddress as () -> Address)
let _ = #selector(Person.workAddress(formatter: ))
I propose removing this kind of selector:

// Should produce selector "street". Note that the method workAddress() is never
// called and its return type only used during type checking
let _ = #selector(getter: me.workAddress().street)

// The above can be rewritten in a cleaner way like the following
let _ = #selector(getter: Address.street)
The proposed way to rewrite the selector elimininates potential confusion about the fact that calling a method inside #selector actually doesn't invoke it.

Grammar

selector → #selector(selector-modiferopt selector-path)

selector-modifier → getter:
selector-modifier → setter:

selector-path → type-identifier . selector-member-path as-disambiguationopt
selector-path → selector-member-path as-disambiguationopt

selector-member-path → identifier
selector-member-path → unqualified-name
selector-member-path → identifier . selector-member-path

as-disambiguation → as type-identifier
For a further rationale on why arbitrary expressions are no longer possible, see the discussion on bugs.swift.org.

Impact on existing code

Code that currently uses this feature needs to be rewritten as described in the example above. I believe, however, that the feature is rarely used so it will affect only very little source code and where it is currently used the proposed update is actually more readable.

Alternatives considered

The only alternative I see is trying to keep the current semantics and implement them for the getter:/setter: selectors.

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


(David Rönnqvist) #3

I noticed in our code that we had one occurrence of

    #selector(SomeClass().someFunction)

which to my eyes looked like a bug.
Disallowing arbitrary expressions looks very reasonable to me and would help catch small mistakes like this one.

···

29 apr. 2016 kl. 16:40 skrev Thorsten Seitz via swift-evolution <swift-evolution@swift.org>:

Looks good to me!

-Thorsten

Am 28.04.2016 um 16:56 schrieb Alex Hoppen via swift-evolution <swift-evolution@swift.org>:

During the implementation of SE-0064 (Referencing Objective-C selector of property getters and setters) I have come across an issue that could be resolved my a minor change to the language and simplify the compiler a lot. I have drafted a proposal below.

Thoughts, comments, especially objections, appreciated.

– Alex

GitHub-Link: https://github.com/ahoppen/swift-evolution/blob/arbitrary-expressions-in-selectors/proposals/0000-arbitrary-expressions-in-selectors.md

Disallow arbitrary expressions in selectors
Proposal: SE-NNNN
Author(s): Alex Hoppen
Status: Draft
Review manager: TBD
Introduction
It is currently possible to write arbitrary expressions inside #selector like the following: #selector(callThisFunc().bar). This complicates the implementation of proposals SE-0064 (Referencing Objective-C selector of property getters and setters) and SE-0062 (Referencing Objective-C key-paths) a lot.

This proposal restricts expressions inside selectors to be a sequence of property or method refernces. I believe this will not be a major restrictions since arbitrary expressions in selectors are probably rarely used, have some rough edges and removing them would simplify the compiler.

Proposed solution
I propose allowed expressions inside #selector (and once implemented #keyPath) to be a series of instance or class members separated by . and allow disambiguating the last component using as.

Detailed design
Examples

class Address: NSObject {
  dynamic var street: String
  dynamic var town: String

  init(street: String, town: String) {
    self.street = street
    self.town = town
  }
}

class Person: NSObject {
  dynamic var name: String
  dynamic var homeAddress: Address

  func workAddress() -> Address {
    // ...
  }

  func workAddress(formatter: AddressFormatter) -> String {
    // ...
  }

  init(name: String, homeAddress: Address) {
    self.name = name
    self.homeAddress = homeAddress
  }
}

let me: Person = ...
The following examples will continue to work:

let _ = #selector(getter: Person.name)
let _ = #selector(getter: me.name)

let _ = #selector(getter: Person.homeAddress.street)
// Could also be written as
let _ = #selector(getter: Address.street)

let _ = #selector(Person.workAddress as () -> Address)
let _ = #selector(Person.workAddress(formatter: ))
I propose removing this kind of selector:

// Should produce selector "street". Note that the method workAddress() is never
// called and its return type only used during type checking
let _ = #selector(getter: me.workAddress().street)

// The above can be rewritten in a cleaner way like the following
let _ = #selector(getter: Address.street)
The proposed way to rewrite the selector elimininates potential confusion about the fact that calling a method inside #selector actually doesn't invoke it.

Grammar

selector → #selector(selector-modiferopt selector-path)

selector-modifier → getter:
selector-modifier → setter:

selector-path → type-identifier . selector-member-path as-disambiguationopt
selector-path → selector-member-path as-disambiguationopt

selector-member-path → identifier
selector-member-path → unqualified-name
selector-member-path → identifier . selector-member-path

as-disambiguation → as type-identifier
For a further rationale on why arbitrary expressions are no longer possible, see the discussion on bugs.swift.org.

Impact on existing code
Code that currently uses this feature needs to be rewritten as described in the example above. I believe, however, that the feature is rarely used so it will affect only very little source code and where it is currently used the proposed update is actually more readable.

Alternatives considered
The only alternative I see is trying to keep the current semantics and implement them for the getter:/setter: selectors.

_______________________________________________
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