I wrote last year about Swift protocol extensions. If you define a method in a protocol extension that isn’t defined as a protocol requirement, it is dispatched statically, whereas methods defined as protocol requirements are dispatched dynamically. (See the original article for a detailed explanation.)

In March, there was an update – an acknowledgement by the Swift team of this shortcoming and a possibility for a change in behaviour.

Now Ole Begemann writes about Kevin Ballard’s post on swift-evolution explaining very nicely why this limitation exists in the first place:

So essentially, while protocols have a virtual function table, protocol extensions do not, and cannot easily have one because a type adopting the protocol won’t necessarily know about all extensions at compile time and therefore cannot add the extension methods to its own vtable. Opinions may vary whether dispatching protocols dynamically all the time would be a viable alternative, but it’s clearly not what the Swift team has in mind for the language.

Kevin’s post is very informative and worth reading in its entirety.


I wrote in August of last year about some potential confusion coming out of the decision to statically dispatch calls to methods defined in a protocol extension that were not defined in the protocol itself. (Whereas calls to methods defined in the protocol are always dynamically dispatched.) This allowed the protocol / extension designer to differentiate between customization points (methods defined in the protocol) and non-customizable code (methods not defined in the protocol, but implemented in an extension).

It looks like Apple’s received some feedback around this, and Doug Gregor acknowledges this is his “Completing Generics” Manifesto. (Update May 5: Austin Zheng has created a formatted version of the manifesto, available on GitHub.) However I’m not optimistic that this will get changed in future versions of Swift, as he puts it in his “Maybe” section:

Maybe

There are a number of features that get discussed from time-to-time, while they could fit into Swift’s generics system, it’s not clear that they belong in Swift at all. The important question for any feature in this category is not “can it be done” or “are there cool things we can express”, but “how can everyday Swift developers benefit from the addition of such a feature?”. Without strong motivating examples, none of these “maybes” will move further along.

Dynamic dispatch for members of protocol extensions

Only the requirements of protocols currently use dynamic dispatch, which can lead
to surprises:

protocol P {
  func foo()
}
extension P {
  func foo() { print(“P.foo()”)
  func bar() { print(“P.bar()”)
}
struct X : P {
  func foo() { print(“X.foo()”)
  func bar() { print(“X.bar()”)
}
let x = X()
x.foo() // X.foo()
x.bar() // X.bar()
let p: P = X()
p.foo() // X.foo()
p.bar() // P.bar()

Swift could adopt a model where members of protocol extensions are dynamically dispatched.

Fingers crossed, but I think the ship has probably sailed on this – I wonder if the change of behaviour would result in more confusing bugs than this quirk of the language did in the first place.


For a few weeks I’ve been working on a new iOS app, written in Swift. The problem domain is super simple: it’s just a list of what I’m calling “reminder snippets” – for now, basic Title / Value pairs – that are editable in the app, and show up in a Today View Snippet.

Screenshot of example app, Neumonic

Having the problem domain so small allows me to experiment with Swift and potential architectures. I’ve been incorporating some lessons I learned from colleagues at my last job, like using immutable model objects (Swift structs, naturally, for value semantics) and Repositories that are responsible for persistence, caching, and so on.

Protocols

I took the Protocol Oriented Programming talk from last year’s WWDC to heart, so every abstraction in the app is a protocol. (I’ve already written a bit about this talk here.) Specifically, I have a ReminderRepository protocol (with MockReminderRepository and PlistReminderRepository implementations) and a Reminder protocol, with one incredibly simple implementation.

public typealias ReminderID = String

public protocol Reminder{
    var id : ReminderID { get }
    var title : String { get }
    var value : String { get }
}

public protocol ReminderRepository {
    func getAllReminders(callback: Result<[Reminder]> -> Void)
    func getReminder(by id: ReminderID, callback: Result<Reminder> -> Void)
    func addReminder(reminder: Reminder, callback: VoidResult -> Void)
    func deleteReminder(reminder: Reminder, callback: VoidResult -> Void)
}

(Result is just a Success/Fail enum that contains some value on success and an error on failure)

Equatable

So far, so good. I really like this architecture. But problems start to crop up when I need to be able to compare Reminders, for instance, in an implementation of deleteReminder:

public func deleteReminder(reminder: Reminder, callback: VoidResult -> Void) {
    // Error. Can't call indexOf because reminder doesn't conform to Equatable
    if let index = reminders.indexOf(reminder) {        
        reminders.removeAtIndex(index)
        callback(.Success)
    } else {
        callback(.Failure)
    }
}

But if we make Reminder conform to Equatable, we lose the ability to have a heterogeneous array of types that conform to Reminder. (Details are in the Protocol Oriented Programming talk. Seriously, watch it.)

The solution given in the talk for general-case comparison is to implement an extension on our protocol. I thought I’d be clever and factor this out into a new protocol, HeterogeneousEquatable, and have Reminder extend from that.

public protocol HeterogeneousEquatable {
    func isEqual(other : Any) -> Bool
}

public extension HeterogeneousEquatable where Self : Equatable {
    public func isEqual(other : Any) -> Bool {
        if let typedOther = other as? Self {
            return typedOther == self
        }
        return false
    }
}

public protocol Reminder : HeterogeneousEquatable { /* ... */ }

Array.indexOf()

Now returning to the reason I initially wanted to make Reminders Equatable – so that I can call reminders.indexOf(someReminder). Right now we still can’t do that, because while we have roughly equivalent functionality, it doesn’t come under the auspices of the Equatable protocol.

Okay, so what if we just extend Array ourselves?

public extension Array where Element : HeterogeneousEquatable {
    func indexOf(element : Element) -> Index? {
        return indexOf({ (currentElement : Element ) -> Bool in
            element == currentElement
        })
    }
}

Great! Everything still compiles. Now we just have to call our overloaded implementation of indexOf:

public func deleteReminder(reminder: Reminder, callback: VoidResult -> Void) {
    // Error again. Sad face.
    if let index = reminders.indexOf(reminder) {        
        reminders.removeAtIndex(index)
        callback(.Success)
    } else {
        callback(.Failure)
    }
}

Now we get Using "Reminder" as a concrete type conforming to protocol "HeterogeneousEquatable" is not supported. Which is true. Reminder isn’t a concrete type. This is a shortcoming in the compiler; it needs things to be nailed down to concrete types here. One can assume that the reason for this is compiler implementation rather than an intentional limitation of the language at a design level. There’s a great Stack Overflow answer by Rob Napier on this.

A Mediocre Solution

Austin Zheng has a blog post about building a HeterogeneousEquatable (which he calls AnyEquatable), which is a good resource if you found my post hard to follow, but he doesn’t look at the case of implementing an extension on Array.

I asked about this on the swift-users mailing list, and Hooman Mehr pointed out that the best way to achieve this is to write a method in an unconditional extension on Array:

extension Array {
    func indexOf(element : HeterogeneousEquatable) -> Index? {
        return self.indexOf { (currentElement : Element) -> Bool in
            if let currentElement = currentElement as? HeterogeneousEquatable {
                return element.equals(currentElement)
            }
            return false
        }
    }
}

This makes me sad. It forces me to pollute the interface of Array with stuff that doesn’t apply in most cases, and it causes confusion about which implementation of indexOf will be called in an instance of [MyType] where MyType implements both Equatable and HeterogeneousEquatable. (The other option is to name it indexOfAny, as Hooman suggests, but I don’t much like that either.)

A Better Solution, Sometimes

I took my quest to the swift-evolution mailing list, and got better results, but they only apply in certain situations.

Dave Abrahams (the guy who gave the Protocol Oriented Programming talk in the first place!) showed that while we can’t use a value of type HeterogeneousEquatable (where the concrete type is unknown) where the requirement is Element : HeterogeneousEquatable, we can do that when the requirement is Element == HeterogeneousEquatable. That’s awesome!

But.

That means that the variable must be typed explicitly as HeterogeneousEquatable. Reminder, even though it extends from HeterogeneousEquatable, is not acceptable.

public extension CollectionType where Generator.Element == HeterogeneousEquatable {
    func indexOf(item: Generator.Element) -> Index? {
        return indexOf {
            return item.isEqual($0)
        }
    }
}

// ...

public func deleteReminder(reminder: Reminder, callback: VoidResult -> Void) {
    if let index = reminders.indexOf(reminder) {        
        reminders.removeAtIndex(index)
        callback(.Success)
    } else {
        callback(.Failure)
    }
}

Type HeterogeneousEquatable does not conform to protocol 'Reminder'

Conclusion

I’ve had to go ahead with the unconditional extension of Array. It’s the only thing that works properly for my use case, at least today.

It is my desperate hope that future versions of Swift will allow for this kind of abstraction – or just go ahead and solve the Equatable problem in a first-party way.

Denouement

Back when the WWDC talk was new there was a big kerfuffle in the Apple development community about the problem of heterogeneous collections of things that conform to a single protocol – how the decision to split protocols into “has Self requirements” and “doesn’t have self requirements” worlds was benefiting the compiler at the expense of the programmer. Michael Tsai has a good overview of the various blogs from that time, all of which are worth a read, including this post from Brent Simmons:

Something like this ought to come naturally and easily to a language, or else that language is not helping me write apps.

I’m generally very positive on Swift – I think when Swift 3.0 hits and the language starts to change a little more slowly, it will be the obvious choice for future projects – but it has some sharp edges for the time being, and if I was to start a production-ready project today, I’m not entirely sure whether I’d choose Swift or Objective-C.