Swift Protocol Extensions overriding

VojtaStavik picture VojtaStavik · Jul 15, 2015 · Viewed 33.4k times · Source

I'm experimenting with Swift protocol extensions and I found this quite confusing behaviour. Could you help me how to get the result I want?

See the comments on the last 4 lines of the code. (You can copy paste it to Xcode7 playground if you want). Thank you!!

protocol Color { }
extension Color {  var color : String { return "Default color" } }

protocol RedColor: Color { }
extension RedColor { var color : String { return "Red color" } }


protocol PrintColor {
    
     func getColor() -> String
}

extension PrintColor where Self: Color {
    
    func getColor() -> String {
        
        return color
    }
}


class A: Color, PrintColor { }
class B: A, RedColor { }


let colorA = A().color // is "Default color" - OK
let colorB = B().color // is "Red color" - OK


let a = A().getColor() // is "Default color" - OK
let b = B().getColor() // is "Default color" BUT I want it to be "Red color"

Answer

matt picture matt · Jul 15, 2015

The short answer is that protocol extensions don't do class polymorphism. This makes a certain sense, because a protocol can be adopted by a struct or enum, and because we wouldn't want the mere adoption of a protocol to introduce dynamic dispatch where it isn't necessary.

Thus, in getColor(), the color instance variable (which may be more accurately written as self.color) doesn't mean what you think it does, because you are thinking class-polymorphically and the protocol is not. So this works:

let colorB = B().color // is "Red color" - OK

...because you are asking a class to resolve color, but this doesn't do what you expect:

let b = B().getColor() // is "Default color" BUT I want it to be "Red color"

...because the getColor method is defined entirely in a protocol extension. You can fix the problem by redefining getColor in B:

class B: A, RedColor {
    func getColor() -> String {
        return self.color
    }
}

Now the class's getColor is called, and it has a polymorphic idea of what self is.