Selector for current method


(Rudolf Adamkovič) #1

Hi there!

in Swift 3, we now have #selector and #keyPath yet there’s still no _cmd like we have in Objective-C.

Example:

class DirectoryListingStub: DirectoryListing {

    var cannedOutput: [Selector: Any?] = [
        #selector(contentsOfDirectory(at:includingPropertiesForKeys:options:)): nil
    ]

    dynamic func contentsOfDirectory(at url: URL, includingPropertiesForKeys keys: [URLResourceKey]?, options: FileManager.DirectoryEnumerationOptions) throws -> [URL] {
        let selector = #selector(contentsOfDirectory(at:includingPropertiesForKeys:options:))
        return cannedOutput[selector] as! [URL]
    }

}

Problem: I had to specify #selector twice.

I though I’d be able to use #function but:

#selector = contentsOfDirectoryAt:includingPropertiesForKeys:options:error:
#function = contentsOfDirectory(at:includingPropertiesForKeys:options:)

It’d be great if #selector (without arguments) returned the current selector.

Or am I missing something?

R+


(Robert Widmann) #2

NSSelectorFromString(#function) works just fine for this already.

···

On Nov 13, 2016, at 6:50 PM, Rudolf Adamkovič via swift-evolution <swift-evolution@swift.org> wrote:

Hi there!

in Swift 3, we now have #selector and #keyPath yet there’s still no _cmd like we have in Objective-C.

Example:

class DirectoryListingStub: DirectoryListing {

   var cannedOutput: [Selector: Any?] = [
       #selector(contentsOfDirectory(at:includingPropertiesForKeys:options:)): nil
   ]

   dynamic func contentsOfDirectory(at url: URL, includingPropertiesForKeys keys: [URLResourceKey]?, options: FileManager.DirectoryEnumerationOptions) throws -> [URL] {
       let selector = #selector(contentsOfDirectory(at:includingPropertiesForKeys:options:))
       return cannedOutput[selector] as! [URL]
   }

}

Problem: I had to specify #selector twice.

I though I’d be able to use #function but:

#selector = contentsOfDirectoryAt:includingPropertiesForKeys:options:error:
#function = contentsOfDirectory(at:includingPropertiesForKeys:options:)

It’d be great if #selector (without arguments) returned the current selector.

Or am I missing something?

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


(Rudolf Adamkovič) #3

NSSelectorFromString(#function) works just fine for this already.

Hi Robert,

it doesn’t work.

NSSelectorFromString(#function)
… returns "contentsOfDirectory(at:includingPropertiesForKeys:options:)"

#selector(DirectoryListingMock.contentsOfDirectory(at:includingPropertiesForKeys:options:))
… returns "contentsOfDirectoryAt:includingPropertiesForKeys:options:error:"

In other words, "NSSelectorFromString(#function)” returns Swift function name, not selector like _cmd or #selector does.

R+

···

On 14 Nov 2016, at 01:01, Robert Widmann <devteam.codafi@gmail.com> wrote:

On Nov 13, 2016, at 6:50 PM, Rudolf Adamkovič via swift-evolution <swift-evolution@swift.org> wrote:

Hi there!

in Swift 3, we now have #selector and #keyPath yet there’s still no _cmd like we have in Objective-C.

Example:

class DirectoryListingStub: DirectoryListing {

  var cannedOutput: [Selector: Any?] = [
      #selector(contentsOfDirectory(at:includingPropertiesForKeys:options:)): nil
  ]

  dynamic func contentsOfDirectory(at url: URL, includingPropertiesForKeys keys: [URLResourceKey]?, options: FileManager.DirectoryEnumerationOptions) throws -> [URL] {
      let selector = #selector(contentsOfDirectory(at:includingPropertiesForKeys:options:))
      return cannedOutput[selector] as! [URL]
  }

}

Problem: I had to specify #selector twice.

I though I’d be able to use #function but:

#selector = contentsOfDirectoryAt:includingPropertiesForKeys:options:error:
#function = contentsOfDirectory(at:includingPropertiesForKeys:options:)

It’d be great if #selector (without arguments) returned the current selector.

Or am I missing something?

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


(Jordan Rose) #4

This doesn’t seem unreasonable, but I’m not sure if that makes it reasonable. :slight_smile: What’s your use case? The stripped-down code seems like it could use any unique key, including #function.

Jordan

···

On Nov 13, 2016, at 15:50, Rudolf Adamkovič via swift-evolution <swift-evolution@swift.org> wrote:

Hi there!

in Swift 3, we now have #selector and #keyPath yet there’s still no _cmd like we have in Objective-C.

Example:

class DirectoryListingStub: DirectoryListing {

   var cannedOutput: [Selector: Any?] = [
       #selector(contentsOfDirectory(at:includingPropertiesForKeys:options:)): nil
   ]

   dynamic func contentsOfDirectory(at url: URL, includingPropertiesForKeys keys: [URLResourceKey]?, options: FileManager.DirectoryEnumerationOptions) throws -> [URL] {
       let selector = #selector(contentsOfDirectory(at:includingPropertiesForKeys:options:))
       return cannedOutput[selector] as! [URL]
   }

}

Problem: I had to specify #selector twice.

I though I’d be able to use #function but:

#selector = contentsOfDirectoryAt:includingPropertiesForKeys:options:error:
#function = contentsOfDirectory(at:includingPropertiesForKeys:options:)

It’d be great if #selector (without arguments) returned the current selector.

Or am I missing something?

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


(Timothy J. Wood) #5

One use case for bare `#selector` would be in patterns like NSTextViewDelegate’s -textView:doCommandBySelector:, where there are many call sites that need to pass the selector (and thus are open to copy-paste errors). I could imagine having a helper to make this less error prone and less verbose:

class SomeView : NSView {
  private func validate(selector: Selector = #selector, action: (Void) -> Void) -> Bool {
    guard checkDelegate(selector) else {
      return
    }
    action()
  }

  @objc func action1(_ sender: AnyObject?) {
    validate {
        // do action
    }
  }

  ...

  @objc func actionN(_ sender: AnyObject?) {
    validate {
        // do action
    }
  }

}

-tim

···

On Nov 14, 2016, at 11:07 AM, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

This doesn’t seem unreasonable, but I’m not sure if that makes it reasonable. :slight_smile: What’s your use case? The stripped-down code seems like it could use any unique key, including #function.

Jordan


(Rudolf Adamkovič) #6

Hi Jordan,

The stripped-down code seems like it could use any unique key, including #function.

That would work only if #function could be used with an argument just like #selector:

class DirectoryListingStub: DirectoryListing {

   var cannedOutput: [Selector: Any?] = [
       #function(contentsOfDirectory(at:includingPropertiesForKeys:options:)): nil
   ]

   func contentsOfDirectory(at url: URL, includingPropertiesForKeys keys: [URLResourceKey]?, options: FileManager.DirectoryEnumerationOptions) throws -> [URL] {
       return cannedOutput[#function] as! [URL]
   }

}

Obviously, this doesn’t work as #function takes no arguments.

There's no way to get #selector for the current method. And there’s no way to get #function for arbitrary method.

R+

···

On 14 Nov 2016, at 20:07, Jordan Rose <jordan_rose@apple.com> wrote:

This doesn’t seem unreasonable, but I’m not sure if that makes it reasonable. :slight_smile: What’s your use case? The stripped-down code seems like it could use any unique key, including #function.

Jordan

On Nov 13, 2016, at 15:50, Rudolf Adamkovič via swift-evolution <swift-evolution@swift.org> wrote:

Hi there!

in Swift 3, we now have #selector and #keyPath yet there’s still no _cmd like we have in Objective-C.

Example:

class DirectoryListingStub: DirectoryListing {

  var cannedOutput: [Selector: Any?] = [
      #selector(contentsOfDirectory(at:includingPropertiesForKeys:options:)): nil
  ]

  dynamic func contentsOfDirectory(at url: URL, includingPropertiesForKeys keys: [URLResourceKey]?, options: FileManager.DirectoryEnumerationOptions) throws -> [URL] {
      let selector = #selector(contentsOfDirectory(at:includingPropertiesForKeys:options:))
      return cannedOutput[selector] as! [URL]
  }

}

Problem: I had to specify #selector twice.

I though I’d be able to use #function but:

#selector = contentsOfDirectoryAt:includingPropertiesForKeys:options:error:
#function = contentsOfDirectory(at:includingPropertiesForKeys:options:)

It’d be great if #selector (without arguments) returned the current selector.

Or am I missing something?

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


(Jordan Rose) #7

Sorry, I see that #function doesn’t work as a drop-in replacement for #selector. What I’m wondering is what you’re actually using this all for. It seems rare to have a dictionary keyed by the name of a function (but not its arguments) and rarer still to need to prepopulate that dictionary. The only use case I can think of is some generalized mock object, but even then I wonder how useful it is in practice.

(Per the original request, remember too that many Swift methods do not have selectors, since they are not exposed to Objective-C.)

Jordan

···

On Nov 15, 2016, at 03:47, Rudolf Adamkovič <salutis@me.com> wrote:

Hi Jordan,

The stripped-down code seems like it could use any unique key, including #function.

That would work only if #function could be used with an argument just like #selector:

class DirectoryListingStub: DirectoryListing {

  var cannedOutput: [Selector: Any?] = [
      #function(contentsOfDirectory(at:includingPropertiesForKeys:options:)): nil
  ]

  func contentsOfDirectory(at url: URL, includingPropertiesForKeys keys: [URLResourceKey]?, options: FileManager.DirectoryEnumerationOptions) throws -> [URL] {
      return cannedOutput[#function] as! [URL]
  }

}

Obviously, this doesn’t work as #function takes no arguments.

There's no way to get #selector for the current method. And there’s no way to get #function for arbitrary method.

R+

On 14 Nov 2016, at 20:07, Jordan Rose <jordan_rose@apple.com> wrote:

This doesn’t seem unreasonable, but I’m not sure if that makes it reasonable. :slight_smile: What’s your use case? The stripped-down code seems like it could use any unique key, including #function.

Jordan

On Nov 13, 2016, at 15:50, Rudolf Adamkovič via swift-evolution <swift-evolution@swift.org> wrote:

Hi there!

in Swift 3, we now have #selector and #keyPath yet there’s still no _cmd like we have in Objective-C.

Example:

class DirectoryListingStub: DirectoryListing {

var cannedOutput: [Selector: Any?] = [
     #selector(contentsOfDirectory(at:includingPropertiesForKeys:options:)): nil
]

dynamic func contentsOfDirectory(at url: URL, includingPropertiesForKeys keys: [URLResourceKey]?, options: FileManager.DirectoryEnumerationOptions) throws -> [URL] {
     let selector = #selector(contentsOfDirectory(at:includingPropertiesForKeys:options:))
     return cannedOutput[selector] as! [URL]
}

}

Problem: I had to specify #selector twice.

I though I’d be able to use #function but:

#selector = contentsOfDirectoryAt:includingPropertiesForKeys:options:error:
#function = contentsOfDirectory(at:includingPropertiesForKeys:options:)

It’d be great if #selector (without arguments) returned the current selector.

Or am I missing something?

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


(Rudolf Adamkovič) #8

What I’m wondering is what you’re actually using this all for.

For example, when testing with Quick (popular testing framework), one can describe a function:

describe(“player.play()”) {
    ...
}

If #function worked like #selector, we could do:

describe(#function(Player.play())) {
    ...
}

This would be safe and refactoring friendly.

P.S. I could do this with #selector but that would require @objc/dynamic which is not ideal.

R+

···

On 15 Nov 2016, at 18:02, Jordan Rose <jordan_rose@apple.com> wrote:

Sorry, I see that #function doesn’t work as a drop-in replacement for #selector. What I’m wondering is what you’re actually using this all for. It seems rare to have a dictionary keyed by the name of a function (but not its arguments) and rarer still to need to prepopulate that dictionary. The only use case I can think of is some generalized mock object, but even then I wonder how useful it is in practice.

(Per the original request, remember too that many Swift methods do not have selectors, since they are not exposed to Objective-C.)

Jordan

On Nov 15, 2016, at 03:47, Rudolf Adamkovič <salutis@me.com <mailto:salutis@me.com>> wrote:

Hi Jordan,

The stripped-down code seems like it could use any unique key, including #function.

That would work only if #function could be used with an argument just like #selector:

class DirectoryListingStub: DirectoryListing {

  var cannedOutput: [Selector: Any?] = [
      #function(contentsOfDirectory(at:includingPropertiesForKeys:options:)): nil
  ]

  func contentsOfDirectory(at url: URL, includingPropertiesForKeys keys: [URLResourceKey]?, options: FileManager.DirectoryEnumerationOptions) throws -> [URL] {
      return cannedOutput[#function] as! [URL]
  }

}

Obviously, this doesn’t work as #function takes no arguments.

There's no way to get #selector for the current method. And there’s no way to get #function for arbitrary method.

R+

On 14 Nov 2016, at 20:07, Jordan Rose <jordan_rose@apple.com <mailto:jordan_rose@apple.com>> wrote:

This doesn’t seem unreasonable, but I’m not sure if that makes it reasonable. :slight_smile: What’s your use case? The stripped-down code seems like it could use any unique key, including #function.

Jordan

On Nov 13, 2016, at 15:50, Rudolf Adamkovič via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi there!

in Swift 3, we now have #selector and #keyPath yet there’s still no _cmd like we have in Objective-C.

Example:

class DirectoryListingStub: DirectoryListing {

var cannedOutput: [Selector: Any?] = [
     #selector(contentsOfDirectory(at:includingPropertiesForKeys:options:)): nil
]

dynamic func contentsOfDirectory(at url: URL, includingPropertiesForKeys keys: [URLResourceKey]?, options: FileManager.DirectoryEnumerationOptions) throws -> [URL] {
     let selector = #selector(contentsOfDirectory(at:includingPropertiesForKeys:options:))
     return cannedOutput[selector] as! [URL]
}

}

Problem: I had to specify #selector twice.

I though I’d be able to use #function but:

#selector = contentsOfDirectoryAt:includingPropertiesForKeys:options:error:
#function = contentsOfDirectory(at:includingPropertiesForKeys:options:)

It’d be great if #selector (without arguments) returned the current selector.

Or am I missing something?

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