Swift Protocol Proposal

Brent Simmons has been writing a Swift Diary covering his attempt at using Swift for a project he’s working on. In Swift Diary #11 Brent writes:

My main problems with Swift are:

  • Collections of protocol-conforming objects don’t work as I need them to.

  • No KVC.

  • No equivalent of NSClassFromString.

There are a lot of reasons why KVC (Key-Value Coding) is valuable on Apple platforms. First, Interface Builder, XIBs, and CoreData all depend upon it as their foundational technology. Not to mention all the other parts of Cocoa that leverage it (like the often troublesome but sometimes really useful bindings) and all the supporting code that’s been written with the flexibility of the Objective-C model in mind. Being able to easily translate a JSON feed into Objective-C model properties was a real strength. Ideally we’d be able to do the same with Swift. Currently we can’t do that. The double edged sword of strict type checking and static dispatch has rendered fundamental approaches to building software for Apple platforms difficult at best and impossible at worst. Neither AppKit nor UIKit could be built with a strict Swift base.

Second, there is no equivalent of NSClassFromString. Frankly, that’s fair enough. There isn’t a Swift equivalent of runtime.h either though and that would be really nice to have. Ideally I’d like to be able to lookup classes, structs, enums and types and to have them well represented in a manner that can be interpreted at runtime. I’m aware of the annoyance and largely undocumented (there’s documentation but @properties were different at one point) results of using @encode. Some manner of querying the type system and interacting dynamically with it would be terrific. I seriously doubt that the internals of the Swift compiler don’t use sizeof or even offsetof from time to time. Now, that’s probably too low level given the potential for Swift objects to not be contiguous in memory with their vtables and properties but in a modern language introspection should be a first class feature. Let us lookup and allocate classes and structs and address their properties or fields in a dynamic fashion.

Protocols. Brent found himself a position where he had to copy an array of objects from one type to another type in order to satisfy the the Swift type system. With a collection of objects, all of which conform to the same protocols, it isn’t possible to return such a collection directly. Brent concludes:

The best way I’ve found to deal with this is to map it.

return messages.map { return $0 as NodeRepresentedObject }

That seems crazy. I’m using map to create an array whose members are absolutely identical to the original array. And if it would let me do that, why not allow my original solution? (Or at least the second solution?)

It is crazy. It allocates a new copy of the collection at the very least. This coercion is required because Swift prefers static dispatch over dynamic. Even in the case of protocols.

Protocols are an interesting case. Structs could be considered pretty much static. They are a collection of things and we’ll pass them by copy and they’re just like a giant CPU natural entity like an integer or a float. Classes can work in static environments. C++ and Java both have pretty static dispatch. So that’s cool, right? (Nobody who isn’t in a position to recompile their entire stack from top to bottom thinks that but, hey, open source and corporate backend peeps can wave their flags here.)

A protocol is an agreed upon method of communicating between two end points. The sender and receiver don’t need to know anything about each other except that they have agreed upon a protocol. This notion flies in the face of the strict type checking of Swift. Protocol conformance (the ability to adopt a lingua franca) is subsumed by a Type, which is the strict description of Swift entities.

Every time you send a message to an Objective-C instance (call a method on an object) the runtime looks it up. There’s a cache and a lot of really fancy optimizations that make it go really fast. Really, if your application is spending a lot of time in objc_msgSend then I’m impressed. Protip: You’re likely dealing with a collection and drop down to CoreFoundation and you’ll gain speed there.

A Protocol is anathema to the Swift language. I know. I watched that session too and it really was compelling. A protocol that can’t behave as an arbitrary communication line between two disparate object lay-outs isn’t really a protocol. It’s a straight jacket.

That’s what Brent was bucking against. He wanted to express something completely natural — he had a collection of instances that could all be addressed in the same manner. He wanted to vend them as such. He properly advertised their abilities and then the compiler balked. The compiler balked because, without coaxing, it was incapable of producing the code that would have solved his issue.

So Brent was forced to make a copy, on every call to his accessor, of a collection. And this in the name of efficiency and speed.

My proposal for Protocols in Swift is this: default to the Objective-C dynamic dispatch method. If objects respond to the protocols then that’s great. If not then error out or flat out explode. Hell, post a warning if you really feel strongly about it. In the cases where Protocols are usable now then make that a fast path. You can do both dynamic dispatch on objects that conform and static dispatch when you’re sure, as you are now, that static dispatch will work.

Protocols should work as you’d expect them to work: if an instance says it conforms to a protocol then it should be able to be addressed as such. If that can’t or won’t happen then we’re not dealing with protocols. We’ve dealing with compile time contracts. That’s a very different, and far more boring, thing.