[swift-evolution] Type-safe selectors

John McCall rjmccall at apple.com
Fri Dec 4 16:33:36 CST 2015


> On Dec 4, 2015, at 2:31 PM, Joe Groff <jgroff at apple.com> wrote:
>> On Dec 4, 2015, at 2:26 PM, Joe Groff <jgroff at apple.com <mailto:jgroff at apple.com>> wrote:
>> 
>>> 
>>> On Dec 4, 2015, at 2:22 PM, Michel Fortin <michel.fortin at michelf.ca <mailto:michel.fortin at michelf.ca>> wrote:
>>> 
>>> Currently in Swift you can get a closure by referring to a method:
>>> 
>>> 	let x = NSString.hasPrefix
>>> 	// x is of type NSString -> String -> Bool
>>> 
>>> Something that would be useful here is if the closure created from Objective-C methods were special in that they could implicitly be converted to a Selector. Instead of writing manually a selector as a string, you'd just have to refer to the method, and you know there's no typo (or else you get a compile-time error). For instance, adding an observer to a NSNotificationCenter would work like this:
>>> 
>>> 	notificationCenter.addObserver(self, selector: MyClass.observeNotification, name: NSSomeNotificationName, object: nil) 
>>> 
>>> This, making sure the correct selector is used for the designated method, seem like it should be somewhat more important in Swift 3 if it includes Evolution Proposal 0005 that suggests many Objective-C methods will be given Swift-specific names.
>>> https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md <https://github.com/apple/swift-evolution/blob/master/proposals/0005-objective-c-name-translation.md>
>>> 
>>> But why stop there when you can go one step further and actually improve type-safety? Instead of taking a Selector parameter, the NSNotificationCenter.addObserver method above could request a @convention(selector) closure of this form:
>>> 
>>> 	@convention(selector) AnyObject -> NSNotification -> Void
>>> 
>>> Under the hood that closure is still a plain selector pointer, but the compiler attaches proper type information to the arguments. Since `addObserver` now declares it wants a selector with the given signature, the compiler can enforce that the arguments and return type for the passed selector are compatible. You 
>> 
>> This is a great approach, and it's mostly exactly what I've had in mind for this. Another nice thing about @convention(selector) is that the compiler could also context-free closures, like with @convention(c), by compiling them down to categories with mangled methods.
>> 
>>> 
>>> Moreover, the @convention(selector) closure you get can then be used as a normal closure inside a Swift method that can be called from Objective-C:
>>> 
>>> 	@objc func callSelector(selector: @convention(selector) NSString -> String -> Bool) -> Bool {
>>> 		let str = NSString(string: "hello")
>>> 		return selector(str)("hell")
>>> 	}
>>> 
>>> 	let x = NSString.hasPrefix
>>> 	// x is of type @convention(selector) NSString -> String -> Bool
>>> 	callSelector(x)
>>> 
>>> So that would make selectors less error-prone because the compiler can type-check them, and you can use selectors in Swift code in a very natural manner.
>> 
>> I would say that 'let x = NSString.hasPrefix' should still give you a @convention(swift) function value by default; that's what we do with method references in general, but you could ask for a @convention(selector) reference explicitly:
>> 
>> let x: @convention(selector) X -> Y -> Z = X.hasPrefix
> 
> One wrinkle you need to consider is the different ARC behavior of method families. @convention(selector) would have to be restricted to referencing methods that don't belong to an usual method family or have unusual ownership rules, or else we'd need multiple @convention(init_selector), (copy_selector), (alloc_selector) etc. conventions.

Or, alternatively, encode that information in the type, which would be necessary for full ObjC fidelity anyway, since ObjC ARC allows you to override conventions with attributes.

The flip side is that, of course, that’s quite a bit more complicated.

John.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151204/a1f6873c/attachment.html>


More information about the swift-evolution mailing list