[Idea] Expression to retrieve the Objective-C selector of a method


(Douglas Gregor) #1

Hi all,

Currently, producing an Objective-C selector in Swift is an error-prone operation. One effectively just writes a string literal and uses it in a context where an ObjectiveC.Selector is expected:

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

There are many points of failure here:

1) The compiler doesn’t syntax-check at all to make sure it’s a valid spelling for a selector
2) The compiler doesn’t look for existing methods with this selector anywhere
3) The mapping from a Swift method name to an Objective-C selector isn’t always immediately obvious (especially for initializers), and will be getting significantly more complicated with the renaming work for Swift 3 (https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md).

I suggest that we add an expression ‘objc_selector(method-reference)` that produces the Objective-C selector for the named method, and produces an error if the method does not have an Objective-C entry point. For example:

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

“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 objc_selector do the work to form the Objective-C selector, we free the programming 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 my “Generalized Naming for Any Function” proposal, which lets us name methods fully, including getters/setters:

  let sel1: Selector = objc_selector(UIView.`insertSubview(_:at:)`) // produces the Selector “insertSubview:atIndex:"
  let sel2: Selector = objc_selector(UIView.`frame.get`) // produces the Selector “frame"

I don’t like the `objc_selector` syntax at all, but otherwise I think this functionality is straightforward.

  - Doug


(Jacob Bandes-Storch) #2

This is a neat idea. Here are some of my thoughts after initial readthrough:

- For symmetry with Obj-C code, how about using "@selector", such as
@selector(UIView.`insertSubview(_:at:)`) ?

- Or, why bother with a new expression? Could the compiler just do this
automatically when it encounters an @objc function being passed as a
Selector? So, you'd simply be able to say "let sel1: Selector =
UIView.`frame.get`"

- Should the migrator offer to convert string-constant selectors to this
form?

- It might be worth considering this in the context of the "type-safe
selectors" idea that was floating around a while back.

- Would it be valid to qualify a function with a subclass's name, when it's
really only defined on the superclass? That is, would
"objc_selector(MyView.`frame.get`)" work even if MyView doesn't override
the `frame` property?

I could see this last one as a potential source of user confusion, because
naming a particular class wouldn't actually tell you which implementation
gets called when performing the selector (that's just the nature of the
Obj-C runtime).

Jacob Bandes-Storch

···

On Sat, Dec 26, 2015 at 11:48 PM, Douglas Gregor via swift-evolution < swift-evolution@swift.org> wrote:

Hi all,

Currently, producing an Objective-C selector in Swift is an error-prone
operation. One effectively just writes a string literal and uses it in a
context where an ObjectiveC.Selector is expected:

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

There are many points of failure here:

1) The compiler doesn’t syntax-check at all to make sure it’s a valid
spelling for a selector
2) The compiler doesn’t look for existing methods with this selector
anywhere
3) The mapping from a Swift method name to an Objective-C selector isn’t
always immediately obvious (especially for initializers), and will be
getting significantly more complicated with the renaming work for Swift 3 (
https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md
).

I suggest that we add an expression ‘objc_selector(method-reference)` that
produces the Objective-C selector for the named method, and produces an
error if the method does not have an Objective-C entry point. For example:

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

“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 objc_selector do the work to form
the Objective-C selector, we free the programming 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 my “Generalized Naming for Any Function”
proposal, which lets us name methods fully, including getters/setters:

        let sel1: Selector = objc_selector(UIView.`insertSubview(_:at:)`)
// produces the Selector “insertSubview:atIndex:"
        let sel2: Selector = objc_selector(UIView.`frame.get`) // produces
the Selector “frame"

I don’t like the `objc_selector` syntax at all, but otherwise I think this
functionality is straightforward.

        - Doug

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


(Joe Groff) #3

Selectors can be seen as "just" a kind of function value. Do we need a new syntax form at all? We ought to be able to turn an unbound function reference like UIView.insertSubview into a selector reference in Selector type context, or maybe a typed @convention(selector) function as discussed in another thread, without any explicit get-a-selector operation.

-Joe

···

On Dec 26, 2015, at 11:48 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

Hi all,

Currently, producing an Objective-C selector in Swift is an error-prone operation. One effectively just writes a string literal and uses it in a context where an ObjectiveC.Selector is expected:

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

There are many points of failure here:

1) The compiler doesn’t syntax-check at all to make sure it’s a valid spelling for a selector
2) The compiler doesn’t look for existing methods with this selector anywhere
3) The mapping from a Swift method name to an Objective-C selector isn’t always immediately obvious (especially for initializers), and will be getting significantly more complicated with the renaming work for Swift 3 (https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md).

I suggest that we add an expression ‘objc_selector(method-reference)` that produces the Objective-C selector for the named method, and produces an error if the method does not have an Objective-C entry point. For example:

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

“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 objc_selector do the work to form the Objective-C selector, we free the programming 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 my “Generalized Naming for Any Function” proposal, which lets us name methods fully, including getters/setters:

  let sel1: Selector = objc_selector(UIView.`insertSubview(_:at:)`) // produces the Selector “insertSubview:atIndex:"
  let sel2: Selector = objc_selector(UIView.`frame.get`) // produces the Selector “frame"

I don’t like the `objc_selector` syntax at all, but otherwise I think this functionality is straightforward.


(Rob Mayoff) #4

Great idea, but why make it a free function instead of a Selector
initializer?

    let sel1 = Selector(UIView.`insertSubview(_:at:)`)
    let sel2 = Selector(UIView.`frame.get`)

Of course if there were such a thing as
GeneralizedFunctionNameLiteralConvertible, we could get a “free” conversion
to Selector:

    control.sendAction(MyTarget.`doSomething(_:)`, to: target, forEvent:
event)


(Michel Fortin) #5

For reference, I'll just point out that there was an interesting discussion about this topic at the beginning of December.
https://lists.swift.org/pipermail/swift-evolution/2015-December/000233.html

···

--
Michel Fortin
https://michelf.ca


(Javier Soto) #6

I would add to what Joe mentioned above the fact that the concept of
"selector" may not mean a whole lot to developers who are first introduced
to Swift without any prior Obj-C or Cocoa experience. Thinking of them as
functions I believe avoids introducing complexity in the form of additional
concepts that one must understand and differentiate ("what's a selector and
why/how is it different from a function value?")

···

On Sun, Dec 27, 2015 at 10:07 AM Joe Groff via swift-evolution < swift-evolution@swift.org> wrote:

> On Dec 26, 2015, at 11:48 PM, Douglas Gregor via swift-evolution < > swift-evolution@swift.org> wrote:
>
> Hi all,
>
> Currently, producing an Objective-C selector in Swift is an error-prone
operation. One effectively just writes a string literal and uses it in a
context where an ObjectiveC.Selector is expected:
>
> control.sendAction(“doSomething:”, to: target, forEvent: event)
>
> There are many points of failure here:
>
> 1) The compiler doesn’t syntax-check at all to make sure it’s a valid
spelling for a selector
> 2) The compiler doesn’t look for existing methods with this selector
anywhere
> 3) The mapping from a Swift method name to an Objective-C selector isn’t
always immediately obvious (especially for initializers), and will be
getting significantly more complicated with the renaming work for Swift 3 (
https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md
).
>
> I suggest that we add an expression ‘objc_selector(method-reference)`
that produces the Objective-C selector for the named method, and produces
an error if the method does not have an Objective-C entry point. For
example:
>
> control.sendAction(objc_selector(MyApplication.doSomething), to:
target, forEvent: event)
>
> “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 objc_selector do the work to form
the Objective-C selector, we free the programming 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 my “Generalized Naming for Any Function”
proposal, which lets us name methods fully, including getters/setters:
>
> let sel1: Selector = objc_selector(UIView.`insertSubview(_:at:)`)
// produces the Selector “insertSubview:atIndex:"
> let sel2: Selector = objc_selector(UIView.`frame.get`) // produces
the Selector “frame"
>
> I don’t like the `objc_selector` syntax at all, but otherwise I think
this functionality is straightforward.

Selectors can be seen as "just" a kind of function value. Do we need a new
syntax form at all? We ought to be able to turn an unbound function
reference like UIView.insertSubview into a selector reference in Selector
type context, or maybe a typed @convention(selector) function as discussed
in another thread, without any explicit get-a-selector operation.

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

--
Javier Soto


(Douglas Gregor) #7

This is a neat idea. Here are some of my thoughts after initial readthrough:

- For symmetry with Obj-C code, how about using "@selector", such as @selector(UIView.`insertSubview(_:at:)`) ?

@ means at-tribute in Swift, whereas this is a specific expression.

- Or, why bother with a new expression? Could the compiler just do this automatically when it encounters an @objc function being passed as a Selector? So, you'd simply be able to say "let sel1: Selector = UIView.`frame.get`"

It could, but I don't think it should: the operation is not common enough that making it implicit would reduce overall syntactic noise, and it would introduce ambiguities between selector- and closure-based APIs.

- Should the migrator offer to convert string-constant selectors to this form?

Yes, absolutely.

- It might be worth considering this in the context of the "type-safe selectors" idea that was floating around a while back.

Yes, I should have referenced that. Apologies!

- Would it be valid to qualify a function with a subclass's name, when it's really only defined on the superclass? That is, would "objc_selector(MyView.`frame.get`)" work even if MyView doesn't override the `frame` property?

Yes. MyView still has that property even if it doesn't override it.

I could see this last one as a potential source of user confusion, because naming a particular class wouldn't actually tell you which implementation gets called when performing the selector (that's just the nature of the Obj-C runtime).

To some extent, that's the nature of overriding. But objective-c allows one to use a selector with an unrelated class, which can certainly be confusing. I feel like that comes from the runtime itself, and isn't something we can avoid with any syntax we pick.

···

Sent from my iPhone

On Dec 27, 2015, at 12:07 AM, Jacob Bandes-Storch <jtbandes@gmail.com> wrote:

Jacob Bandes-Storch

On Sat, Dec 26, 2015 at 11:48 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:
Hi all,

Currently, producing an Objective-C selector in Swift is an error-prone operation. One effectively just writes a string literal and uses it in a context where an ObjectiveC.Selector is expected:

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

There are many points of failure here:

1) The compiler doesn’t syntax-check at all to make sure it’s a valid spelling for a selector
2) The compiler doesn’t look for existing methods with this selector anywhere
3) The mapping from a Swift method name to an Objective-C selector isn’t always immediately obvious (especially for initializers), and will be getting significantly more complicated with the renaming work for Swift 3 (https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md).

I suggest that we add an expression ‘objc_selector(method-reference)` that produces the Objective-C selector for the named method, and produces an error if the method does not have an Objective-C entry point. For example:

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

“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 objc_selector do the work to form the Objective-C selector, we free the programming 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 my “Generalized Naming for Any Function” proposal, which lets us name methods fully, including getters/setters:

        let sel1: Selector = objc_selector(UIView.`insertSubview(_:at:)`) // produces the Selector “insertSubview:atIndex:"
        let sel2: Selector = objc_selector(UIView.`frame.get`) // produces the Selector “frame"

I don’t like the `objc_selector` syntax at all, but otherwise I think this functionality is straightforward.

        - Doug

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


(James Campbell) #8

Totally agree with that proposal, I think we should do that as a temporary step but also look to reduce the need for selectors in favour of closures.

As I think a lot of the behaviour of selectors
Could be replicated by existing swift features.

···

Sent from my iPhone

On 30 Dec 2015, at 12:54, Michel Fortin via swift-evolution <swift-evolution@swift.org> wrote:

For reference, I'll just point out that there was an interesting discussion about this topic at the beginning of December.
https://lists.swift.org/pipermail/swift-evolution/2015-December/000233.html

--
Michel Fortin
https://michelf.ca

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


(Russ Bishop) #9

I agree, we don’t need anything special for this. Let a function reference decay into a selector where appropriate.

For that matter I want properties and subscripts to decay into getter/setter function references in contextually appropriate places as well, but haven’t proposed it yet.

—russ

···

On Dec 27, 2015, at 10:07 AM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

Selectors can be seen as "just" a kind of function value. Do we need a new syntax form at all? We ought to be able to turn an unbound function reference like UIView.insertSubview into a selector reference in Selector type context, or maybe a typed @convention(selector) function as discussed in another thread, without any explicit get-a-selector operation.

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


(Félix Cloutier) #10

Would it be possible to add properties to closures/method objects?

Right now, it's possible to write:

@objc
class Foo : NSObject {
  func doSomething(value: Int) -> Int {
    return value + 1
  }
}

let method = Foo.doSomething

Maybe we could have Foo.doSomething.selector for @objc methods?

Félix

···

Le 27 déc. 2015 à 15:55:31, Javier Soto via swift-evolution <swift-evolution@swift.org> a écrit :

I would add to what Joe mentioned above the fact that the concept of "selector" may not mean a whole lot to developers who are first introduced to Swift without any prior Obj-C or Cocoa experience. Thinking of them as functions I believe avoids introducing complexity in the form of additional concepts that one must understand and differentiate ("what's a selector and why/how is it different from a function value?")
On Sun, Dec 27, 2015 at 10:07 AM Joe Groff via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

> On Dec 26, 2015, at 11:48 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
> Hi all,
>
> Currently, producing an Objective-C selector in Swift is an error-prone operation. One effectively just writes a string literal and uses it in a context where an ObjectiveC.Selector is expected:
>
> control.sendAction(“doSomething:”, to: target, forEvent: event)
>
> There are many points of failure here:
>
> 1) The compiler doesn’t syntax-check at all to make sure it’s a valid spelling for a selector
> 2) The compiler doesn’t look for existing methods with this selector anywhere
> 3) The mapping from a Swift method name to an Objective-C selector isn’t always immediately obvious (especially for initializers), and will be getting significantly more complicated with the renaming work for Swift 3 (https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md).
>
> I suggest that we add an expression ‘objc_selector(method-reference)` that produces the Objective-C selector for the named method, and produces an error if the method does not have an Objective-C entry point. For example:
>
> control.sendAction(objc_selector(MyApplication.doSomething), to: target, forEvent: event)
>
> “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 objc_selector do the work to form the Objective-C selector, we free the programming 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 my “Generalized Naming for Any Function” proposal, which lets us name methods fully, including getters/setters:
>
> let sel1: Selector = objc_selector(UIView.`insertSubview(_:at:)`) // produces the Selector “insertSubview:atIndex:"
> let sel2: Selector = objc_selector(UIView.`frame.get`) // produces the Selector “frame"
>
> I don’t like the `objc_selector` syntax at all, but otherwise I think this functionality is straightforward.

Selectors can be seen as "just" a kind of function value. Do we need a new syntax form at all? We ought to be able to turn an unbound function reference like UIView.insertSubview into a selector reference in Selector type context, or maybe a typed @convention(selector) function as discussed in another thread, without any explicit get-a-selector operation.

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


(Joe Groff) #11

Sent from my iPhone

This is a neat idea. Here are some of my thoughts after initial readthrough:

- For symmetry with Obj-C code, how about using "@selector", such as @selector(UIView.`insertSubview(_:at:)`) ?

@ means at-tribute in Swift, whereas this is a specific expression.

- Or, why bother with a new expression? Could the compiler just do this automatically when it encounters an @objc function being passed as a Selector? So, you'd simply be able to say "let sel1: Selector = UIView.`frame.get`"

It could, but I don't think it should: the operation is not common enough that making it implicit would reduce overall syntactic noise, and it would introduce ambiguities between selector- and closure-based APIs.

Maybe we can make constructor-like "Selector(Class.method)" syntax work (and "Selector(getterFor:/setterFor: Class.property)" for property accessors) instead of introducing a new magic function name.

-Joe

···

On Dec 29, 2015, at 12:19 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:
On Dec 27, 2015, at 12:07 AM, Jacob Bandes-Storch <jtbandes@gmail.com <mailto:jtbandes@gmail.com>> wrote:

- Should the migrator offer to convert string-constant selectors to this form?

Yes, absolutely.

- It might be worth considering this in the context of the "type-safe selectors" idea that was floating around a while back.

Yes, I should have referenced that. Apologies!

- Would it be valid to qualify a function with a subclass's name, when it's really only defined on the superclass? That is, would "objc_selector(MyView.`frame.get`)" work even if MyView doesn't override the `frame` property?

Yes. MyView still has that property even if it doesn't override it.

I could see this last one as a potential source of user confusion, because naming a particular class wouldn't actually tell you which implementation gets called when performing the selector (that's just the nature of the Obj-C runtime).

To some extent, that's the nature of overriding. But objective-c allows one to use a selector with an unrelated class, which can certainly be confusing. I feel like that comes from the runtime itself, and isn't something we can avoid with any syntax we pick.

Jacob Bandes-Storch

On Sat, Dec 26, 2015 at 11:48 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Hi all,

Currently, producing an Objective-C selector in Swift is an error-prone operation. One effectively just writes a string literal and uses it in a context where an ObjectiveC.Selector is expected:

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

There are many points of failure here:

1) The compiler doesn’t syntax-check at all to make sure it’s a valid spelling for a selector
2) The compiler doesn’t look for existing methods with this selector anywhere
3) The mapping from a Swift method name to an Objective-C selector isn’t always immediately obvious (especially for initializers), and will be getting significantly more complicated with the renaming work for Swift 3 (https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md).

I suggest that we add an expression ‘objc_selector(method-reference)` that produces the Objective-C selector for the named method, and produces an error if the method does not have an Objective-C entry point. For example:

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

“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 objc_selector do the work to form the Objective-C selector, we free the programming 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 my “Generalized Naming for Any Function” proposal, which lets us name methods fully, including getters/setters:

        let sel1: Selector = objc_selector(UIView.`insertSubview(_:at:)`) // produces the Selector “insertSubview:atIndex:"
        let sel2: Selector = objc_selector(UIView.`frame.get`) // produces the Selector “frame"

I don’t like the `objc_selector` syntax at all, but otherwise I think this functionality is straightforward.

        - 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


(Joe Groff) #12

Once you have a normal function value, it's not guaranteed you can recover any identity from it, since an arbitrary T -> U doesn't necessarily correspond to an @objc method. I'm proposing we do this by type context, similar to how we form C function pointers and blocks. Just like you can do:

let fptr: @convention(c) (Double) -> Double = sqrt

to get the function pointer for `sqrt`, you could say:

let sel: Selector = Foo.doSomething

to get the selector for `doSomething`.

-Joe

···

On Dec 28, 2015, at 10:46 AM, Félix Cloutier <felixcca@yahoo.ca> wrote:

Would it be possible to add properties to closures/method objects?

Right now, it's possible to write:

@objc
class Foo : NSObject {
  func doSomething(value: Int) -> Int {
    return value + 1
  }
}

let method = Foo.doSomething

Maybe we could have Foo.doSomething.selector for @objc methods?


(Félix Cloutier) #13

I really only was talking about the case where the compiler knows that it's an @objc method (with the understanding that the information is lost as soon as you make an unattributed T -> U closure out of it).

Either syntax would make me happy.

Félix

···

Le 28 déc. 2015 à 13:49:22, Joe Groff <jgroff@apple.com> a écrit :

On Dec 28, 2015, at 10:46 AM, Félix Cloutier <felixcca@yahoo.ca <mailto:felixcca@yahoo.ca>> wrote:

Would it be possible to add properties to closures/method objects?

Right now, it's possible to write:

@objc
class Foo : NSObject {
  func doSomething(value: Int) -> Int {
    return value + 1
  }
}

let method = Foo.doSomething

Maybe we could have Foo.doSomething.selector for @objc methods?

Once you have a normal function value, it's not guaranteed you can recover any identity from it, since an arbitrary T -> U doesn't necessarily correspond to an @objc method. I'm proposing we do this by type context, similar to how we form C function pointers and blocks. Just like you can do:

let fptr: @convention(c) (Double) -> Double = sqrt

to get the function pointer for `sqrt`, you could say:

let sel: Selector = Foo.doSomething

to get the selector for `doSomething`.

-Joe


(James Campbell) #14

What if you could just refer to it by pointing to a special property ?

button.addTarget( class.prototype.handlePress)

If it has parameters these could be specified like so

button.addTarget(class.prototype.handlePress(sender:))

···

Sent from my iPhone

On 29 Dec 2015, at 21:46, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 29, 2015, at 12:19 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

Sent from my iPhone

On Dec 27, 2015, at 12:07 AM, Jacob Bandes-Storch <jtbandes@gmail.com> wrote:

This is a neat idea. Here are some of my thoughts after initial readthrough:

- For symmetry with Obj-C code, how about using "@selector", such as @selector(UIView.`insertSubview(_:at:)`) ?

@ means at-tribute in Swift, whereas this is a specific expression.

- Or, why bother with a new expression? Could the compiler just do this automatically when it encounters an @objc function being passed as a Selector? So, you'd simply be able to say "let sel1: Selector = UIView.`frame.get`"

It could, but I don't think it should: the operation is not common enough that making it implicit would reduce overall syntactic noise, and it would introduce ambiguities between selector- and closure-based APIs.

Maybe we can make constructor-like "Selector(Class.method)" syntax work (and "Selector(getterFor:/setterFor: Class.property)" for property accessors) instead of introducing a new magic function name.

-Joe

- Should the migrator offer to convert string-constant selectors to this form?

Yes, absolutely.

- It might be worth considering this in the context of the "type-safe selectors" idea that was floating around a while back.

Yes, I should have referenced that. Apologies!

- Would it be valid to qualify a function with a subclass's name, when it's really only defined on the superclass? That is, would "objc_selector(MyView.`frame.get`)" work even if MyView doesn't override the `frame` property?

Yes. MyView still has that property even if it doesn't override it.

I could see this last one as a potential source of user confusion, because naming a particular class wouldn't actually tell you which implementation gets called when performing the selector (that's just the nature of the Obj-C runtime).

To some extent, that's the nature of overriding. But objective-c allows one to use a selector with an unrelated class, which can certainly be confusing. I feel like that comes from the runtime itself, and isn't something we can avoid with any syntax we pick.

Jacob Bandes-Storch

On Sat, Dec 26, 2015 at 11:48 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:
Hi all,

Currently, producing an Objective-C selector in Swift is an error-prone operation. One effectively just writes a string literal and uses it in a context where an ObjectiveC.Selector is expected:

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

There are many points of failure here:

1) The compiler doesn’t syntax-check at all to make sure it’s a valid spelling for a selector
2) The compiler doesn’t look for existing methods with this selector anywhere
3) The mapping from a Swift method name to an Objective-C selector isn’t always immediately obvious (especially for initializers), and will be getting significantly more complicated with the renaming work for Swift 3 (https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md).

I suggest that we add an expression ‘objc_selector(method-reference)` that produces the Objective-C selector for the named method, and produces an error if the method does not have an Objective-C entry point. For example:

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

“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 objc_selector do the work to form the Objective-C selector, we free the programming 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 my “Generalized Naming for Any Function” proposal, which lets us name methods fully, including getters/setters:

        let sel1: Selector = objc_selector(UIView.`insertSubview(_:at:)`) // produces the Selector “insertSubview:atIndex:"
        let sel2: Selector = objc_selector(UIView.`frame.get`) // produces the Selector “frame"

I don’t like the `objc_selector` syntax at all, but otherwise I think this functionality is straightforward.

        - Doug

_______________________________________________
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

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


(James Campbell) #15

What if selectors arguments could be imported into swift to take a closure instead ?

This would fit into the proposal to rewrite the imported objective c Apis

So

- addAction:(Selector)action

Becomes

addAction(action:(AnyObject)->Void)

Instead of

addAction(action:String)

Like it does now.

···

Sent from my iPhone

On 29 Dec 2015, at 21:46, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 29, 2015, at 12:19 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

Sent from my iPhone

On Dec 27, 2015, at 12:07 AM, Jacob Bandes-Storch <jtbandes@gmail.com> wrote:

This is a neat idea. Here are some of my thoughts after initial readthrough:

- For symmetry with Obj-C code, how about using "@selector", such as @selector(UIView.`insertSubview(_:at:)`) ?

@ means at-tribute in Swift, whereas this is a specific expression.

- Or, why bother with a new expression? Could the compiler just do this automatically when it encounters an @objc function being passed as a Selector? So, you'd simply be able to say "let sel1: Selector = UIView.`frame.get`"

It could, but I don't think it should: the operation is not common enough that making it implicit would reduce overall syntactic noise, and it would introduce ambiguities between selector- and closure-based APIs.

Maybe we can make constructor-like "Selector(Class.method)" syntax work (and "Selector(getterFor:/setterFor: Class.property)" for property accessors) instead of introducing a new magic function name.

-Joe

- Should the migrator offer to convert string-constant selectors to this form?

Yes, absolutely.

- It might be worth considering this in the context of the "type-safe selectors" idea that was floating around a while back.

Yes, I should have referenced that. Apologies!

- Would it be valid to qualify a function with a subclass's name, when it's really only defined on the superclass? That is, would "objc_selector(MyView.`frame.get`)" work even if MyView doesn't override the `frame` property?

Yes. MyView still has that property even if it doesn't override it.

I could see this last one as a potential source of user confusion, because naming a particular class wouldn't actually tell you which implementation gets called when performing the selector (that's just the nature of the Obj-C runtime).

To some extent, that's the nature of overriding. But objective-c allows one to use a selector with an unrelated class, which can certainly be confusing. I feel like that comes from the runtime itself, and isn't something we can avoid with any syntax we pick.

Jacob Bandes-Storch

On Sat, Dec 26, 2015 at 11:48 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:
Hi all,

Currently, producing an Objective-C selector in Swift is an error-prone operation. One effectively just writes a string literal and uses it in a context where an ObjectiveC.Selector is expected:

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

There are many points of failure here:

1) The compiler doesn’t syntax-check at all to make sure it’s a valid spelling for a selector
2) The compiler doesn’t look for existing methods with this selector anywhere
3) The mapping from a Swift method name to an Objective-C selector isn’t always immediately obvious (especially for initializers), and will be getting significantly more complicated with the renaming work for Swift 3 (https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md).

I suggest that we add an expression ‘objc_selector(method-reference)` that produces the Objective-C selector for the named method, and produces an error if the method does not have an Objective-C entry point. For example:

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

“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 objc_selector do the work to form the Objective-C selector, we free the programming 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 my “Generalized Naming for Any Function” proposal, which lets us name methods fully, including getters/setters:

        let sel1: Selector = objc_selector(UIView.`insertSubview(_:at:)`) // produces the Selector “insertSubview:atIndex:"
        let sel2: Selector = objc_selector(UIView.`frame.get`) // produces the Selector “frame"

I don’t like the `objc_selector` syntax at all, but otherwise I think this functionality is straightforward.

        - Doug

_______________________________________________
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

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


(Brent Royal-Gordon) #16

What if selectors arguments could be imported into swift to take a closure instead ?

This would fit into the proposal to rewrite the imported objective c Apis

So

- addAction:(Selector)action

Becomes

addAction(action:(AnyObject)->Void)

Instead of

addAction(action:String)

Like it does now.

Actually, it comes in as addAction(action: Selector), not String. You can initialize a Selector from a string literal.

Three questions about your proposal:

1. Where does "AnyObject -> Void" come from? The only signature information in a selector is the (minimum) number of arguments. Those arguments can be of any type, and

2. How are we supposed to implement this? You need to somehow convert a closure (a pointer to a bunch of captured variables with a pointer to a function embedded inside it) into a selector (a pointer to a table of selectors inside the Objective-C runtime, which does not do any normal memory management); I just don't see how you make that work. Saying "let's do this thing" doesn't mean it's *possible* to do the thing.

3. What about other uses for selectors? addAction() is all well and good, but you also need removeAction(), and Swift closures don't have stable identities to test with.

···

--
Brent Royal-Gordon
Architechies


(Árpád Goretity) #17

+1 for that. Closures are much more swift-y than selectors (and honestly,
even in Objective-C, selectors are a pain to use). This would definitely be
nice, although I'm not quite sure if it's possible with reasonable effort.
Selectors are very, very different beasts.

···

On Wed, Dec 30, 2015 at 10:56 AM, James Campbell via swift-evolution < swift-evolution@swift.org> wrote:

What if selectors arguments could be imported into swift to take a closure
instead ?

This would fit into the proposal to rewrite the imported objective c Apis

So

- addAction:(Selector)action

Becomes

addAction(action:(AnyObject)->Void)

Instead of

addAction(action:String)

Like it does now.

Sent from my iPhone

On 29 Dec 2015, at 21:46, Joe Groff via swift-evolution < > swift-evolution@swift.org> wrote:

On Dec 29, 2015, at 12:19 PM, Douglas Gregor via swift-evolution < > swift-evolution@swift.org> wrote:

Sent from my iPhone

On Dec 27, 2015, at 12:07 AM, Jacob Bandes-Storch <jtbandes@gmail.com> > wrote:

This is a neat idea. Here are some of my thoughts after initial
readthrough:

- For symmetry with Obj-C code, how about using "@selector", such as
@selector(UIView.`insertSubview(_:at:)`) ?

@ means at-tribute in Swift, whereas this is a specific expression.

- Or, why bother with a new expression? Could the compiler just do this
automatically when it encounters an @objc function being passed as a
Selector? So, you'd simply be able to say "let sel1: Selector =
UIView.`frame.get`"

It could, but I don't think it should: the operation is not common enough
that making it implicit would reduce overall syntactic noise, and it would
introduce ambiguities between selector- and closure-based APIs.

Maybe we can make constructor-like "Selector(Class.method)" syntax work
(and "Selector(getterFor:/setterFor: Class.property)" for property
accessors) instead of introducing a new magic function name.

-Joe

- Should the migrator offer to convert string-constant selectors to this
form?

Yes, absolutely.

- It might be worth considering this in the context of the "type-safe
selectors" idea that was floating around a while back.

Yes, I should have referenced that. Apologies!

- Would it be valid to qualify a function with a subclass's name, when
it's really only defined on the superclass? That is, would
"objc_selector(MyView.`frame.get`)" work even if MyView doesn't override
the `frame` property?

Yes. MyView still has that property even if it doesn't override it.

I could see this last one as a potential source of user confusion, because
naming a particular class wouldn't actually tell you which implementation
gets called when performing the selector (that's just the nature of the
Obj-C runtime).

To some extent, that's the nature of overriding. But objective-c allows
one to use a selector with an unrelated class, which can certainly be
confusing. I feel like that comes from the runtime itself, and isn't
something we can avoid with any syntax we pick.

Jacob Bandes-Storch

On Sat, Dec 26, 2015 at 11:48 PM, Douglas Gregor via swift-evolution < > swift-evolution@swift.org> wrote:

Hi all,

Currently, producing an Objective-C selector in Swift is an error-prone
operation. One effectively just writes a string literal and uses it in a
context where an ObjectiveC.Selector is expected:

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

There are many points of failure here:

1) The compiler doesn’t syntax-check at all to make sure it’s a valid
spelling for a selector
2) The compiler doesn’t look for existing methods with this selector
anywhere
3) The mapping from a Swift method name to an Objective-C selector isn’t
always immediately obvious (especially for initializers), and will be
getting significantly more complicated with the renaming work for Swift 3 (
https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md
).

I suggest that we add an expression ‘objc_selector(method-reference)`
that produces the Objective-C selector for the named method, and produces
an error if the method does not have an Objective-C entry point. For
example:

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

“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 objc_selector do the work to form
the Objective-C selector, we free the programming 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 my “Generalized Naming for Any Function”
proposal, which lets us name methods fully, including getters/setters:

        let sel1: Selector = objc_selector(UIView.`insertSubview(_:at:)`)
// produces the Selector “insertSubview:atIndex:"
        let sel2: Selector = objc_selector(UIView.`frame.get`) //
produces the Selector “frame"

I don’t like the `objc_selector` syntax at all, but otherwise I think
this functionality is straightforward.

        - Doug

_______________________________________________
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

_______________________________________________
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

--
Author of the Sparkling language
http://h2co3.org/


(James Campbell) #18

These are very good points.

Actually, it comes in as addAction(action: Selector), not String. You can initialize a Selector from a string literal.

Yes :slight_smile: should have looked it up before I tried to remember it off the top of my head.

Three questions about your proposal:

1. Where does "AnyObject -> Void" come from? The only signature information in a selector is the (minimum) number of arguments. Those arguments can be of any type, and

Well I would want to know what selectors people would us:

One with one argument tend to be for events like button actions and notifications which could be replaced by closures. We could deprecate or provide warnings when trying to use the Selector Apis in swift.

Others with more tend to be for canPerformSelector which is replaced by optionals.

The one edge case not handled is nsinvocation or performSelector, I would be interested why people use this use case and how we would replace it in swift (if at all).

2. How are we supposed to implement this? You need to somehow convert a closure (a pointer to a bunch of captured variables with a pointer to a function embedded inside it) into a selector (a pointer to a table of selectors inside the Objective-C runtime, which does not do any normal memory management); I just don't see how you make that work. Saying "let's do this thing" doesn't mean it's *possible* to do the thing.

I get that they are different but I had the idea that the compiler could generate a unique name for each closure which when referenced by a selector it would invoke.

But this would be irrelevant if we moved towards closure Apis.

3. What about other uses for selectors? addAction() is all well and good, but you also need removeAction(), and Swift closures don't have stable identities to test with.

I question when we use things such as removeAction? I've only used addAction. But I guess again if we moved to closure Apis this point would be moot.

To me the only case that needs selectors is performSelector or Nsinvocation. The others can be replaced by closures and the selector api to be deprecated or to show a warning in swift :slight_smile: (Xcode could even help migrate by moving it to a closure that calls the function the selector was pointing to)

I'm not a compiler expert so I rely on the swift team to tell me what's possible (although at this early stage I think it's more important to figure out what we want and not be bound by what's possible right now)

···

--
Brent Royal-Gordon
Architechies


(James Campbell) #19

In the performSelector and nsinvocation case.

Are people using it for existing functions in which case type safety is important.

But if it's for dynamic calling of a method ( for example for a visitor pattern) then I don't think there is any safety that can easily be applied via a special syntax and if it can it would be done another way.

I think in most cases the selector has been replaced in swift.

···

Sent from my iPhone

On 30 Dec 2015, at 11:21, James Campbell <james@supmenow.com> wrote:

These are very good points.

Actually, it comes in as addAction(action: Selector), not String. You can initialize a Selector from a string literal.

Yes :slight_smile: should have looked it up before I tried to remember it off the top of my head.

Three questions about your proposal:

1. Where does "AnyObject -> Void" come from? The only signature information in a selector is the (minimum) number of arguments. Those arguments can be of any type, and

Well I would want to know what selectors people would us:

One with one argument tend to be for events like button actions and notifications which could be replaced by closures. We could deprecate or provide warnings when trying to use the Selector Apis in swift.

Others with more tend to be for canPerformSelector which is replaced by optionals.

The one edge case not handled is nsinvocation or performSelector, I would be interested why people use this use case and how we would replace it in swift (if at all).

2. How are we supposed to implement this? You need to somehow convert a closure (a pointer to a bunch of captured variables with a pointer to a function embedded inside it) into a selector (a pointer to a table of selectors inside the Objective-C runtime, which does not do any normal memory management); I just don't see how you make that work. Saying "let's do this thing" doesn't mean it's *possible* to do the thing.

I get that they are different but I had the idea that the compiler could generate a unique name for each closure which when referenced by a selector it would invoke.

But this would be irrelevant if we moved towards closure Apis.

3. What about other uses for selectors? addAction() is all well and good, but you also need removeAction(), and Swift closures don't have stable identities to test with.

I question when we use things such as removeAction? I've only used addAction. But I guess again if we moved to closure Apis this point would be moot.

To me the only case that needs selectors is performSelector or Nsinvocation. The others can be replaced by closures and the selector api to be deprecated or to show a warning in swift :slight_smile: (Xcode could even help migrate by moving it to a closure that calls the function the selector was pointing to)

I'm not a compiler expert so I rely on the swift team to tell me what's possible (although at this early stage I think it's more important to figure out what we want and not be bound by what's possible right now)

--
Brent Royal-Gordon
Architechies


(Jean-Daniel) #20

How would the closure based API work with Interface Builder ?

···

Le 30 déc. 2015 à 12:21, James Campbell via swift-evolution <swift-evolution@swift.org> a écrit :

These are very good points.

Actually, it comes in as addAction(action: Selector), not String. You can initialize a Selector from a string literal.

Yes :slight_smile: should have looked it up before I tried to remember it off the top of my head.

Three questions about your proposal:

1. Where does "AnyObject -> Void" come from? The only signature information in a selector is the (minimum) number of arguments. Those arguments can be of any type, and

Well I would want to know what selectors people would us:

One with one argument tend to be for events like button actions and notifications which could be replaced by closures. We could deprecate or provide warnings when trying to use the Selector Apis in swift.

Others with more tend to be for canPerformSelector which is replaced by optionals.

The one edge case not handled is nsinvocation or performSelector, I would be interested why people use this use case and how we would replace it in swift (if at all).

2. How are we supposed to implement this? You need to somehow convert a closure (a pointer to a bunch of captured variables with a pointer to a function embedded inside it) into a selector (a pointer to a table of selectors inside the Objective-C runtime, which does not do any normal memory management); I just don't see how you make that work. Saying "let's do this thing" doesn't mean it's *possible* to do the thing.

I get that they are different but I had the idea that the compiler could generate a unique name for each closure which when referenced by a selector it would invoke.

But this would be irrelevant if we moved towards closure Apis.

3. What about other uses for selectors? addAction() is all well and good, but you also need removeAction(), and Swift closures don't have stable identities to test with.

I question when we use things such as removeAction? I've only used addAction. But I guess again if we moved to closure Apis this point would be moot.

To me the only case that needs selectors is performSelector or Nsinvocation. The others can be replaced by closures and the selector api to be deprecated or to show a warning in swift :slight_smile: (Xcode could even help migrate by moving it to a closure that calls the function the selector was pointing to)

I'm not a compiler expert so I rely on the swift team to tell me what's possible (although at this early stage I think it's more important to figure out what we want and not be bound by what's possible right now)