Protocol extension code executed instead of class code


(Diego Sánchez) #1

Consider the following code

protocol MyProtocol {
    func doSomething()
}

extension MyProtocol {
    func doSomething() {
        print("default impl")
    }
}

class A: MyProtocol {}

class B: A {
    func doSomething() {
        print("B impl")
    }
}

let a: MyProtocol = A()
a.doSomething() // Prints "default impl"
let b: MyProtocol = B()
b.doSomething() // Prints "default impl" instead of "B impl"!

Now let's override doSomething in A...

class A: MyProtocol {
    func doSomething() {
        print("A impl")
    }
}

class B: A {
     override func doSomething() {
        print("B impl")
    }
}

let a: MyProtocol = A()
a.doSomething() // Now it prints "A impl"
let b: MyProtocol = B()
b.doSomething() // Now it prints "B impl"

That's clearly inconsistent. I would expect to print "B impl" in the first
case; or maybe always "default impl" (I highly prefer the first option)


(Joe Groff) #2

If you don't say 'override', you're not overriding anything, but defining a logically independent method. In the first example, `doSomething` isn't really a member of `A`, so it's not overrideable by subclasses, and the declaration of `B.doSomething` just shadows the protocol extension implementation instead of overriding it. This is admittedly weird, so we do have some proposals floating to improve things by implicitly mirroring protocol methods as class methods when a class conforms to a protocol.

-Joe

···

On Feb 20, 2016, at 4:41 AM, Diego Sánchez via swift-users <swift-users@swift.org> wrote:

Consider the following code

protocol MyProtocol {
    func doSomething()
}

extension MyProtocol {
    func doSomething() {
        print("default impl")
    }
}

class A: MyProtocol {}

class B: A {
    func doSomething() {
        print("B impl")
    }
}

let a: MyProtocol = A()
a.doSomething() // Prints "default impl"
let b: MyProtocol = B()
b.doSomething() // Prints "default impl" instead of "B impl"!

Now let's override doSomething in A...

class A: MyProtocol {
    func doSomething() {
        print("A impl")
    }
}

class B: A {
     override func doSomething() {
        print("B impl")
    }
}

let a: MyProtocol = A()
a.doSomething() // Now it prints "A impl"
let b: MyProtocol = B()
b.doSomething() // Now it prints "B impl"

That's clearly inconsistent. I would expect to print "B impl" in the first case; or maybe always "default impl" (I highly prefer the first option)


(Diego Sánchez) #3

That would be great, thanks for the heads up!

···

2016-02-20 23:22 GMT+00:00 Joe Groff <jgroff@apple.com>:

> On Feb 20, 2016, at 4:41 AM, Diego Sánchez via swift-users < > swift-users@swift.org> wrote:
>
> Consider the following code
>
> protocol MyProtocol {
> func doSomething()
> }
>
> extension MyProtocol {
> func doSomething() {
> print("default impl")
> }
> }
>
> class A: MyProtocol {}
>
> class B: A {
> func doSomething() {
> print("B impl")
> }
> }
>
> let a: MyProtocol = A()
> a.doSomething() // Prints "default impl"
> let b: MyProtocol = B()
> b.doSomething() // Prints "default impl" instead of "B impl"!
>
> Now let's override doSomething in A...
>
> class A: MyProtocol {
> func doSomething() {
> print("A impl")
> }
> }
>
> class B: A {
> override func doSomething() {
> print("B impl")
> }
> }
>
> let a: MyProtocol = A()
> a.doSomething() // Now it prints "A impl"
> let b: MyProtocol = B()
> b.doSomething() // Now it prints "B impl"
>
> That's clearly inconsistent. I would expect to print "B impl" in the
first case; or maybe always "default impl" (I highly prefer the first
option)

If you don't say 'override', you're not overriding anything, but defining
a logically independent method. In the first example, `doSomething` isn't
really a member of `A`, so it's not overrideable by subclasses, and the
declaration of `B.doSomething` just shadows the protocol extension
implementation instead of overriding it. This is admittedly weird, so we do
have some proposals floating to improve things by implicitly mirroring
protocol methods as class methods when a class conforms to a protocol.

-Joe