[swift-evolution] Type-safe selectors

Kevin Ballard kevin at sb.org
Sat Dec 5 21:35:12 CST 2015

On Sat, Dec 5, 2015, at 06:00 PM, Joe Groff wrote:
> > How is this type-safe? You're using as! in there (and silently ignoring
> > the message if the receiver is wrong wouldn't be any better). If I send
> > a selector to the wrong receiver, it's still going to crash.
> I think this would be better emitted like a category on MyObject than on
> NSObject.

Going back and reading your original suggestion about generating
closures, I think we're talking about this differently. If I understand
it right, your original suggestion for generating closures basically
just solves the problem of forgetting to mark a method as @objc, right?
In that case, putting the category on MyObject instead of NSObject is
absolutely the right thing to do. My arguments here are actually about
Michel Fortin's claim:

> The fact that the selector lives separately from its target object makes things difficult because the expected target type is almost always going to be AnyObject. Implicit conversions cannot happen safely in the direction SubType to BaseType for the arguments, including the target object. That makes Joe Groff's approach the only type-safe solution: make an extension of the base object and generate a method that does what you want.

Which is in the context of the fact that @convention(selector) MyObject
-> Args -> Ret encodes the receiver type, but the problem is the
selector is sent to AnyObject, so having the receiver type in there is
basically false type-safety (it looks like it's strongly-typed but it's
actually not as that type information will be thrown away before the
selector is used). I'm not really sure why Michel claimed that your
closure suggestion was a solution to this problem, because the only
reasonable behavior one can use in such a category emitted on
AnyObject/swift base class is to fatalError, which is no better than
what happens if the selector simply isn't implemented.

Ultimately, given the premise that @convention(selector) T -> Args ->
Ret exists, generating those methods on the receiver type with mangled
selector names seems like reasonable behavior. I just don't think
@convention(selector) should exist.

> There's plenty of useful space between "no type safety" and "perfect type safety", IMO.

In principle I agree. My basic argument here is that
@convention(selector) provides so little actual type safety that it's
not worth the language complexity. And I also worry that providing
functionality that appears to be strongly-typed but doesn't actually
provide any typing guarantees in practice will end up as a safety hazard
for unwary programmers.

It's also worth pointing out that my alternative suggestion of simply
providing some syntax to explicitly get a Selector from a method could
still use your closure-generating idea to work for non- at objc methods.
Heck, we don't even really need syntax for this, we could just say that
unbound method references can resolve to Selectors in addition to
function types (just as the primary suggestion here allows method
references to resolve to @convention(selector) functions in addition to
@convention(swift) functions).

-Kevin Ballard

More information about the swift-evolution mailing list