Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.

Join them; it only takes a minute:

Sign up
Join the Stack Overflow community to:
  1. Ask programming questions
  2. Answer and help your peers
  3. Get recognized for your expertise

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!!

//: Playground - noun: a place where people can play

import UIKit

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"
share|improve this question

1 Answer 1

up vote 6 down vote accepted

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.

share|improve this answer
    
Good discussion here: nomothetis.svbtle.com/the-ghost-of-swift-bugs-future – matt Jul 15 at 14:05
    
Thank you for your answer. Let me redefine my question: Is there a way how to modify some instance variable simply by adding a protocol to the class? Let's say we have class A and A.text is "Hello" . But class A:Protocol would cause A.text to be "Ciao"? – VojtaStavik Jul 15 at 14:50
    
No, that would make no sense. Again, think about what a protocol is for. It would be terrible if mere adoption of a protocol had more power than the class itself to say what something should be or do. — However, read the article I pointed you to, because it shows that if an object reference is typed as the protocol, the protocol's implementation can be preferred over the adopter's. – matt Jul 15 at 14:52
    
OK, got it. Thank you for your help! – VojtaStavik Jul 15 at 14:54

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.