[swift-user]Unexpected behavior of protocol extension.


(Zhao Xin) #1

See below code.

protocol Foo {

    func bar()

}

extension Foo {

    func bar() {

        print("I am bar.")

    }

}

class A:Foo {

    func output() {

        print(type(of:self)) // prints "B".

        self.bar() // prints "I am bar."

        (self as! B).bar() // prints "I am B."

    }

}

class B:A {

    func bar() {

        print("I am B.")

    }

}

let b = B()

b.output()

I thought `self.bar()` would do the same as `(self as! B).bar()`. It
didn't. In my opinion, `type(of:self) is B.type`, so they should be the
same, shouldn't they?

Zhaoxin


(Игорь Никитин) #2

Looks like a bug according to dispatch rules (here <https://medium.com/ios-os-x-development/swift-protocol-extension-method-dispatch-6a6bf270ba94#.8zlhlu8s6> and here <https://nomothetis.svbtle.com/the-ghost-of-swift-bugs-future?utm_campaign=iOS+Dev+Weekly&utm_medium=web&utm_source=iOS_Dev_Weekly_Issue_203>. Also similar question on SO <http://stackoverflow.com/questions/34847318/swift-protocol-extension-method-dispatch-with-superclass-and-subclass>)
It should call dynamic bar implementation

···

20 сент. 2016 г., в 5:11, Zhao Xin via swift-users <swift-users@swift.org> написал(а):

See below code.

protocol Foo {
    func bar()
}

extension Foo {
    func bar() {
        print("I am bar.")
    }
}

class A:Foo {
    func output() {
        print(type(of:self)) // prints "B".
        self.bar() // prints "I am bar."
        (self as! B).bar() // prints "I am B."
    }
}

class B:A {
    func bar() {
        print("I am B.")
    }
}

let b = B()
b.output()

I thought `self.bar()` would do the same as `(self as! B).bar()`. It didn't. In my opinion, `type(of:self) is B.type`, so they should be the same, shouldn't they?

Zhaoxin
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Adrian Zubarev) #3

I can’t tell you the reason, but to me it feels like it’s doing the following thing:

+ - - (Type: B) - - +

                  >
func bar() + - + (Type: A) - - + < - - - - - - - - - - - - - - - - - - - - +
              > > >

+ - - - - - - - + func output() + - + (Protocol: Foo) - - + — - self.bar() - + - (self as! B).bar() - +
                > > > >
                + - - - - - - - + (default) func bar() | <- - - - - - - - +
                                > >
                                + - - - - - - - - - - - - +
class A:Foo {
     
    func bar() {}
     
    func output() {
        print(type(of:self))
        self.bar()
        (self as! B).bar()
    }
}

class B:A {

    override func bar() {
        print("I am B.")
    }
}
Would solve this temporarily.

And there we are again with the same discussion if custom implementation of protocol members, which have default implementation, should have the override keyword or not.

Imagine your code like this (not valid code):

protocol Foo {
    func bar()
}

extension Foo {
    func bar() {
        print("I am bar.")
    }
}

class A : Foo {
     
    func output() {
         
        print(type(of:self))
        default.bar() // fallback an call directly the default implementation whenever needed
        self.bar() // will print "I am bar." on A().output() but should print "I am B." if Self == B
        (self as! B).bar()
    }
}

class B : A {

    override func bar() {
        print("I am B.")
    }
}
I still think default implementations should be called through something like default. + whenever you override a default implementation you’d need override. There is a discussion going on: Mark protocol methods with their protocol. I clearly did not solved your issue, but I might have wake your interest to participate. :wink:

···

--
Adrian Zubarev
Sent with Airmail

Am 20. September 2016 um 04:13:22, Zhao Xin via swift-users (swift-users@swift.org) schrieb:

See below code.

protocol Foo {
func bar()
}

extension Foo {
func bar() {
print("I am bar.")
}
}

class A:Foo {
func output() {
print(type(of:self)) // prints "B".
self.bar() // prints "I am bar."
(self as! B).bar() // prints "I am B."
}
}

class B:A {
func bar() {
print("I am B.")
}
}

let b = B()
b.output()

I thought `self.bar()` would do the same as `(self as! B).bar()`. It didn't. In my opinion, `type(of:self) is B.type`, so they should be the same, shouldn't they?

Zhaoxin
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Zhao Xin) #4

Thank you to Игорь Никитин and Adrian Zubarev. Now I can convince myself
for this behavior.

As Adrian's example shows, there is no `bar()` implemented in `class A`, so
there is no `override func bar()` in class B`. My thought that `self.bar()`
would do the same as `(self as! B).bar()`, is called "dynamic binding",
which is basing on the `override`. Since there is no `override`, there is
no "dynamic binding". I thought "dynamic binding" was basing on dynamic
type of `self`. It was not. I was wrong.

The behavior is clear now. In class A's `self.bar()`, the runtime finds
that there is no implementation of `bar()` in `class A`, so it calls the
`bar` in protocol extension. In class A's `(self as! B).bar()`, as `class
B` contains the implementation of `bar()`, the runtime calls it.

Zhaoxin

···

On Tue, Sep 20, 2016 at 4:21 PM, Adrian Zubarev via swift-evolution < swift-evolution@swift.org> wrote:

I can’t tell you the reason, but to me it feels like it’s doing the
following thing:

+ - - (Type: B) - - +
> >
> func bar() + - + (Type: A) - - + < - - - - - - - - - - - - - - - - - - - - +
> > > >
+ - - - - - - - + func output() + - + (Protocol: Foo) - - + — - self.bar() - + - (self as! B).bar() - +
                > > > >
                + - - - - - - - + (default) func bar() | <- - - - - - - - +
                                > >
                                + - - - - - - - - - - - - +

class A:Foo {

    func bar() {}

    func output() {
        print(type(of:self))
        self.bar()
        (self as! B).bar()
    }
}

class B:A {

    override func bar() {
        print("I am B.")
    }
}

Would solve this temporarily.

And there we are again with the same discussion if custom implementation
of protocol members, which have default implementation, should have the
override keyword or not.

Imagine your code like this (not valid code):

protocol Foo {
    func bar()
}

extension Foo {
    func bar() {
        print("I am bar.")
    }
}

class A : Foo {

    func output() {

        print(type(of:self))
        default.bar() // fallback an call directly the default implementation whenever needed
        self.bar() // will print "I am bar." on A().output() but should print "I am B." if Self == B
        (self as! B).bar()
    }
}

class B : A {

    override func bar() {
        print("I am B.")
    }
}

I still think default implementations should be called through something
like default. + whenever you override a default implementation you’d need
override. There is a discussion going on: Mark protocol methods with
their protocol. I clearly did not solved your issue, but I might have
wake your interest to participate. :wink:

--
Adrian Zubarev
Sent with Airmail

Am 20. September 2016 um 04:13:22, Zhao Xin via swift-users (
swift-users@swift.org) schrieb:

See below code.

protocol Foo {

    func bar()

}

extension Foo {

    func bar() {

        print("I am bar.")

    }

}

class A:Foo {

    func output() {

        print(type(of:self)) // prints "B".

        self.bar() // prints "I am bar."

        (self as! B).bar() // prints "I am B."

    }

}

class B:A {

    func bar() {

        print("I am B.")

    }

}

let b = B()

b.output()

I thought `self.bar()` would do the same as `(self as! B).bar()`. It
didn't. In my opinion, `type(of:self) is B.type`, so they should be the
same, shouldn't they?

Zhaoxin
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


#5

I think there is a deeper issue that may be worth exploring here.

Notably, when one class presents a member function, its subclasses ought to
use “override” when they reimplement that method themselves, regardless of
where the superclass’s version comes from.

In the original post, the class “A” expresses (by conforming to protocol
“Foo”) that it has a member function “bar()”, and “B” is a subclass of “A”
which wants its own definition of “bar()”.

It seems to me that “B” should not care whether “A” rolled its own
implementation of “bar()” or used the default implementation provided by
“Foo”.

From the perspective of “B”, its superclass “A” promises to have a member

function “bar()”, so “B” should need to use the `override` keyword just
like it would when overriding any other method.

To illustrate this more clearly, suppose that “Foo” and “A: Foo” are
defined in a 3rd-party library, while “B: A” is written in a client module.

If the library changes to give “A” its own custom implementation of
“bar()”, that *should not* affect client code—because the class “A” still
conforms to “Foo” so it still is known to have a “bar()” method—but right
now it *does*:

With the status quo, the simple change of moving a function between a
protocol extension and a conforming class currently requires downstream
source-code modifications in clients (in this case, adding `override` to
“B.bar()”).

I propose that `override` should be required in subclasses on any method
which the superclass proffers as a customization point, no matter the
provenance of that claim.

Nevin

···

On Tue, Sep 20, 2016 at 8:01 AM, Zhao Xin via swift-evolution < swift-evolution@swift.org> wrote:

Thank you to Игорь Никитин and Adrian Zubarev. Now I can convince myself
for this behavior.

As Adrian's example shows, there is no `bar()` implemented in `class A`,
so there is no `override func bar()` in class B`. My thought that `self.bar()`
would do the same as `(self as! B).bar()`, is called "dynamic binding",
which is basing on the `override`. Since there is no `override`, there is
no "dynamic binding". I thought "dynamic binding" was basing on dynamic
type of `self`. It was not. I was wrong.

The behavior is clear now. In class A's `self.bar()`, the runtime finds
that there is no implementation of `bar()` in `class A`, so it calls the
`bar` in protocol extension. In class A's `(self as! B).bar()`, as `class
B` contains the implementation of `bar()`, the runtime calls it.

Zhaoxin

On Tue, Sep 20, 2016 at 4:21 PM, Adrian Zubarev via swift-evolution < > swift-evolution@swift.org> wrote:

I can’t tell you the reason, but to me it feels like it’s doing the
following thing:

+ - - (Type: B) - - +
> >
> func bar() + - + (Type: A) - - + < - - - - - - - - - - - - - - - - - - - - +
> > > >
+ - - - - - - - + func output() + - + (Protocol: Foo) - - + — - self.bar() - + - (self as! B).bar() - +
                > > > >
                + - - - - - - - + (default) func bar() | <- - - - - - - - +
                                > >
                                + - - - - - - - - - - - - +

class A:Foo {

    func bar() {}

    func output() {
        print(type(of:self))
        self.bar()
        (self as! B).bar()
    }
}

class B:A {

    override func bar() {
        print("I am B.")
    }
}

Would solve this temporarily.

And there we are again with the same discussion if custom implementation
of protocol members, which have default implementation, should have the
override keyword or not.

Imagine your code like this (not valid code):

protocol Foo {
    func bar()
}

extension Foo {
    func bar() {
        print("I am bar.")
    }
}

class A : Foo {

    func output() {

        print(type(of:self))
        default.bar() // fallback an call directly the default implementation whenever needed
        self.bar() // will print "I am bar." on A().output() but should print "I am B." if Self == B
        (self as! B).bar()
    }
}

class B : A {

    override func bar() {
        print("I am B.")
    }
}

I still think default implementations should be called through something
like default. + whenever you override a default implementation you’d
need override. There is a discussion going on: Mark protocol methods
with their protocol. I clearly did not solved your issue, but I might
have wake your interest to participate. :wink:

--
Adrian Zubarev
Sent with Airmail

Am 20. September 2016 um 04:13:22, Zhao Xin via swift-users (
swift-users@swift.org) schrieb:

See below code.

protocol Foo {

    func bar()

}

extension Foo {

    func bar() {

        print("I am bar.")

    }

}

class A:Foo {

    func output() {

        print(type(of:self)) // prints "B".

        self.bar() // prints "I am bar."

        (self as! B).bar() // prints "I am B."

    }

}

class B:A {

    func bar() {

        print("I am B.")

    }

}

let b = B()

b.output()

I thought `self.bar()` would do the same as `(self as! B).bar()`. It
didn't. In my opinion, `type(of:self) is B.type`, so they should be the
same, shouldn't they?

Zhaoxin
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Goffredo Marocchi) #6

This would make for hilarious debugging session if you have the misfortune of using a third party binary framework that gets updated and provide default implementations for some methods in the protocol extensions.

When Java 8 also decided to blur the lines between classes (implementations) and interfaces (equivalent of protocols on this side of the fence more or less... anyways they represent behaviours/API contracts), they also provided a very simple rule to determine on the code would behave at runtime.

Extending Interfaces That Contain Default Methods

When you extend an interface that contains a default method, you can do the following:

Not mention the default method at all, which lets your extended interface inherit the default method.
Redeclare the default method, which makes it abstract.
Redefine the default method, which overrides it.

https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html

I am not sure why protocol extension need to differ so much and present dispatch rules that are potentially very confusing.

Casting at runtime should *never* change what implementation of a method gets called.
For a safe by default language the fact that this can occur is quite puzzling and worrying. I am not sure the cost of implementing the current static/dynamic dispatch rules for default methods in protocol extensions is worth it to say it bluntly, but please enlighten me if I am missing an obvious huge pink elephant in the room here.

···

Sent from my iPhone

On 20 Sep 2016, at 16:18, Nevin Brackett-Rozinsky via swift-evolution <swift-evolution@swift.org> wrote:

I think there is a deeper issue that may be worth exploring here.

Notably, when one class presents a member function, its subclasses ought to use “override” when they reimplement that method themselves, regardless of where the superclass’s version comes from.

In the original post, the class “A” expresses (by conforming to protocol “Foo”) that it has a member function “bar()”, and “B” is a subclass of “A” which wants its own definition of “bar()”.

It seems to me that “B” should not care whether “A” rolled its own implementation of “bar()” or used the default implementation provided by “Foo”.

From the perspective of “B”, its superclass “A” promises to have a member function “bar()”, so “B” should need to use the `override` keyword just like it would when overriding any other method.

To illustrate this more clearly, suppose that “Foo” and “A: Foo” are defined in a 3rd-party library, while “B: A” is written in a client module.

If the library changes to give “A” its own custom implementation of “bar()”, that *should not* affect client code—because the class “A” still conforms to “Foo” so it still is known to have a “bar()” method—but right now it *does*:

With the status quo, the simple change of moving a function between a protocol extension and a conforming class currently requires downstream source-code modifications in clients (in this case, adding `override` to “B.bar()”).

I propose that `override` should be required in subclasses on any method which the superclass proffers as a customization point, no matter the provenance of that claim.

Nevin

On Tue, Sep 20, 2016 at 8:01 AM, Zhao Xin via swift-evolution <swift-evolution@swift.org> wrote:
Thank you to Игорь Никитин and Adrian Zubarev. Now I can convince myself for this behavior.

As Adrian's example shows, there is no `bar()` implemented in `class A`, so there is no `override func bar()` in class B`. My thought that `self.bar()` would do the same as `(self as! B).bar()`, is called "dynamic binding", which is basing on the `override`. Since there is no `override`, there is no "dynamic binding". I thought "dynamic binding" was basing on dynamic type of `self`. It was not. I was wrong.

The behavior is clear now. In class A's `self.bar()`, the runtime finds that there is no implementation of `bar()` in `class A`, so it calls the `bar` in protocol extension. In class A's `(self as! B).bar()`, as `class B` contains the implementation of `bar()`, the runtime calls it.

Zhaoxin

On Tue, Sep 20, 2016 at 4:21 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:
I can’t tell you the reason, but to me it feels like it’s doing the following thing:

+ - - (Type: B) - - +
> >
> func bar() + - + (Type: A) - - + < - - - - - - - - - - - - - - - - - - - - +
> > > >
+ - - - - - - - + func output() + - + (Protocol: Foo) - - + — - self.bar() - + - (self as! B).bar() - +
                > > > >
                + - - - - - - - + (default) func bar() | <- - - - - - - - +
                                > >
                                + - - - - - - - - - - - - +
class A:Foo {
     
    func bar() {}
     
    func output() {
        print(type(of:self))
        self.bar()
        (self as! B).bar()
    }
}

class B:A {

    override func bar() {
        print("I am B.")
    }
}
Would solve this temporarily.

And there we are again with the same discussion if custom implementation of protocol members, which have default implementation, should have the override keyword or not.

Imagine your code like this (not valid code):

protocol Foo {
    func bar()
}

extension Foo {
    func bar() {
        print("I am bar.")
    }
}

class A : Foo {
     
    func output() {
         
        print(type(of:self))
        default.bar() // fallback an call directly the default implementation whenever needed
        self.bar() // will print "I am bar." on A().output() but should print "I am B." if Self == B
        (self as! B).bar()
    }
}

class B : A {

    override func bar() {
        print("I am B.")
    }
}
I still think default implementations should be called through something like default. + whenever you override a default implementation you’d need override. There is a discussion going on: Mark protocol methods with their protocol. I clearly did not solved your issue, but I might have wake your interest to participate. :wink:

--
Adrian Zubarev
Sent with Airmail

Am 20. September 2016 um 04:13:22, Zhao Xin via swift-users (swift-users@swift.org) schrieb:

See below code.

protocol Foo {
    func bar()
}

extension Foo {
    func bar() {
        print("I am bar.")
    }
}

class A:Foo {
    func output() {
        print(type(of:self)) // prints "B".
        self.bar() // prints "I am bar."
        (self as! B).bar() // prints "I am B."
    }
}

class B:A {
    func bar() {
        print("I am B.")
    }
}

let b = B()
b.output()

I thought `self.bar()` would do the same as `(self as! B).bar()`. It didn't. In my opinion, `type(of:self) is B.type`, so they should be the same, shouldn't they?

Zhaoxin
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Zhao Xin) #7

I understand your point on "adding additional `override` to
re-implementation of default method in protocol extension". However, I
don't stand for it.

If you use `override`, that means `B` could use `super.bar()` to get the
original `bar()` implementation. Then if `class A` implement `bar()`
someday. The `super.bar()` call in `class B` will be ambitious, it could be
`A.bar()` or `Foo.bar()`. That ambiguity is the same as the multiple object
inherences languages like c++. We all know that Swift can only inherit to
one object. That is why the behavior is what it is now.

Zhaoxin

···

On Tue, Sep 20, 2016 at 11:18 PM, Nevin Brackett-Rozinsky < nevin.brackettrozinsky@gmail.com> wrote:

I think there is a deeper issue that may be worth exploring here.

Notably, when one class presents a member function, its subclasses ought
to use “override” when they reimplement that method themselves, regardless
of where the superclass’s version comes from.

In the original post, the class “A” expresses (by conforming to protocol
“Foo”) that it has a member function “bar()”, and “B” is a subclass of “A”
which wants its own definition of “bar()”.

It seems to me that “B” should not care whether “A” rolled its own
implementation of “bar()” or used the default implementation provided by
“Foo”.

From the perspective of “B”, its superclass “A” promises to have a member
function “bar()”, so “B” should need to use the `override` keyword just
like it would when overriding any other method.

To illustrate this more clearly, suppose that “Foo” and “A: Foo” are
defined in a 3rd-party library, while “B: A” is written in a client module.

If the library changes to give “A” its own custom implementation of
“bar()”, that *should not* affect client code—because the class “A” still
conforms to “Foo” so it still is known to have a “bar()” method—but right
now it *does*:

With the status quo, the simple change of moving a function between a
protocol extension and a conforming class currently requires downstream
source-code modifications in clients (in this case, adding `override` to
“B.bar()”).

I propose that `override` should be required in subclasses on any method
which the superclass proffers as a customization point, no matter the
provenance of that claim.

Nevin

On Tue, Sep 20, 2016 at 8:01 AM, Zhao Xin via swift-evolution < > swift-evolution@swift.org> wrote:

Thank you to Игорь Никитин and Adrian Zubarev. Now I can convince myself
for this behavior.

As Adrian's example shows, there is no `bar()` implemented in `class A`,
so there is no `override func bar()` in class B`. My thought that `self.bar()`
would do the same as `(self as! B).bar()`, is called "dynamic binding",
which is basing on the `override`. Since there is no `override`, there is
no "dynamic binding". I thought "dynamic binding" was basing on dynamic
type of `self`. It was not. I was wrong.

The behavior is clear now. In class A's `self.bar()`, the runtime finds
that there is no implementation of `bar()` in `class A`, so it calls the
`bar` in protocol extension. In class A's `(self as! B).bar()`, as `class
B` contains the implementation of `bar()`, the runtime calls it.

Zhaoxin

On Tue, Sep 20, 2016 at 4:21 PM, Adrian Zubarev via swift-evolution < >> swift-evolution@swift.org> wrote:

I can’t tell you the reason, but to me it feels like it’s doing the
following thing:

+ - - (Type: B) - - +
> >
> func bar() + - + (Type: A) - - + < - - - - - - - - - - - - - - - - - - - - +
> > > >
+ - - - - - - - + func output() + - + (Protocol: Foo) - - + — - self.bar() - + - (self as! B).bar() - +
                > > > >
                + - - - - - - - + (default) func bar() | <- - - - - - - - +
                                > >
                                + - - - - - - - - - - - - +

class A:Foo {

    func bar() {}

    func output() {
        print(type(of:self))
        self.bar()
        (self as! B).bar()
    }
}

class B:A {

    override func bar() {
        print("I am B.")
    }
}

Would solve this temporarily.

And there we are again with the same discussion if custom implementation
of protocol members, which have default implementation, should have the
override keyword or not.

Imagine your code like this (not valid code):

protocol Foo {
    func bar()
}

extension Foo {
    func bar() {
        print("I am bar.")
    }
}

class A : Foo {

    func output() {

        print(type(of:self))
        default.bar() // fallback an call directly the default implementation whenever needed
        self.bar() // will print "I am bar." on A().output() but should print "I am B." if Self == B
        (self as! B).bar()
    }
}

class B : A {

    override func bar() {
        print("I am B.")
    }
}

I still think default implementations should be called through something
like default. + whenever you override a default implementation you’d
need override. There is a discussion going on: Mark protocol methods
with their protocol. I clearly did not solved your issue, but I might
have wake your interest to participate. :wink:

--
Adrian Zubarev
Sent with Airmail

Am 20. September 2016 um 04:13:22, Zhao Xin via swift-users (
swift-users@swift.org) schrieb:

See below code.

protocol Foo {

    func bar()

}

extension Foo {

    func bar() {

        print("I am bar.")

    }

}

class A:Foo {

    func output() {

        print(type(of:self)) // prints "B".

        self.bar() // prints "I am bar."

        (self as! B).bar() // prints "I am B."

    }

}

class B:A {

    func bar() {

        print("I am B.")

    }

}

let b = B()

b.output()

I thought `self.bar()` would do the same as `(self as! B).bar()`. It
didn't. In my opinion, `type(of:self) is B.type`, so they should be the
same, shouldn't they?

Zhaoxin
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Vladimir) #8

Btw,..

I think there is a deeper issue that may be worth exploring here.

Notably, when one class presents a member function, its subclasses ought to
use “override” when they reimplement that method themselves, regardless of
where the superclass’s version comes from.

In the original post, the class “A” expresses (by conforming to protocol
“Foo”) that it has a member function “bar()”, and “B” is a subclass of “A”
which wants its own definition of “bar()”.

It seems to me that “B” should not care whether “A” rolled its own
implementation of “bar()” or used the default implementation provided by “Foo”.

From the perspective of “B”, its superclass “A” promises to have a member
function “bar()”, so “B” should need to use the `override` keyword just
like it would when overriding any other method.

See how "my" suggestion regarding requiring a keyword for implementation of protocol requirement (but with `override` keyword instead of `implement`) can be very helpful here
(And Karl, seems like "your" suggestion will not help here - I mean we'll have to change bar() definition in B in case A implement its own bar())

In this case, initially, B.bar() must be marked with "override" as it is implementing protocol's requirement. *And* this will "protect" B class in future if class A will implement its own bar() method:

protocol Foo {
  func bar()
}

extension Foo {
  func bar() {
    print("I am bar.")
  }
}

class A:Foo {
}

class B:A {
  *override* func bar() { // currently protocol impelentation
    print("I am B.")
  }
}

and then if

class A:Foo {
  override func bar() {...}
}

,B's definition will not be changed.

Then we have a question regarding super.bar() inside B.bar(), i.e. should it be accessible or not. I believe we should consider if it could be implemented, so in case A has no bar(), super.bar() will call protocol's implementation, otherwise (if A contains bar()) - A.bar() will be called. Don't know if this is what very hard to implement.
Probably as first step super.bar() will not be allowed inside of protocol implementation.

Swift allows for protocols to have default *implementations* for requirements. And *also* Swift allows you to *not* implement requirement that has default implementation in conformed type.
When you don't implement such requirement in type - the type *inherits* that implementation. We have classical inheritance scheme like in inheritance of super type's method. When you override super type's method you have to use `override`. I believe overriding the inherited default implementation of requirement - also should be marked with `override`.

Then, Swift allows protocol to have extension in any source file in project. You can have no default implementation *at moment of writing* your type, but you can have such default implementation *at moment of compilation*. So, as soon as we *can't* know if protocol's requirement will *actually* have default implementation during the compilation - logically that we should use `override` to mark each method/prop defined as implementation of protocol, to suppose that there *is* default implementation which will be *overridden* by our custom implementation.

···

On 20.09.2016 18:18, Nevin Brackett-Rozinsky via swift-evolution wrote:

To illustrate this more clearly, suppose that “Foo” and “A: Foo” are
defined in a 3rd-party library, while “B: A” is written in a client module.

If the library changes to give “A” its own custom implementation of
“bar()”, that *should not* affect client code—because the class “A” still
conforms to “Foo” so it still is known to have a “bar()” method—but right
now it *does*:

With the status quo, the simple change of moving a function between a
protocol extension and a conforming class currently requires downstream
source-code modifications in clients (in this case, adding `override` to
“B.bar()”).

I propose that `override` should be required in subclasses on any method
which the superclass proffers as a customization point, no matter the
provenance of that claim.

Nevin

On Tue, Sep 20, 2016 at 8:01 AM, Zhao Xin via swift-evolution > <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

    Thank you to Игорь Никитин and Adrian Zubarev. Now I can convince
    myself for this behavior.

    As Adrian's example shows, there is no `bar()` implemented in `class
    A`, so there is no `override func bar()` in class B`. My thought
    that `self.bar()` would do the same as `(self as! B).bar()`, is called
    "dynamic binding", which is basing on the `override`. Since there is no
    `override`, there is no "dynamic binding". I thought "dynamic binding"
    was basing on dynamic type of `self`. It was not. I was wrong.

    The behavior is clear now. In class A's `self.bar()`, the runtime finds
    that there is no implementation of `bar()` in `class A`, so it calls
    the `bar` in protocol extension. In class A's `(self as! B).bar()`, as
    `class B` contains the implementation of `bar()`, the runtime calls it.

    Zhaoxin

    On Tue, Sep 20, 2016 at 4:21 PM, Adrian Zubarev via swift-evolution > <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

        I can’t tell you the reason, but to me it feels like it’s doing the
        following thing:

        >+ - - (Type: B) - - + | | | func bar() + - + (Type: A) - - + < - -
        - - - - - - - - - - - - - - - - - - + | | | | + - - - - - - - +
        func output() + - + (Protocol: Foo) - - + — - self.bar() - + -
        (self as! B).bar() - + | | | | + - - - - - - - + (default) func
        bar() | <- - - - - - - - + | | + - - - - - - - - - - - - + |

        >class A:Foo { func bar() {} func output() { print(type(of:self))
        self.bar() (self as! B).bar() } } class B:A { override func bar() {
        print("I am B.") } } |

        Would solve this temporarily.

        And there we are again with the same discussion if custom
        implementation of protocol members, which have default
        implementation, should have the |override| keyword or not.

        Imagine your code like this (not valid code):

        >protocol Foo { func bar() } extension Foo { func bar() { print("I
        am bar.") } } class A : Foo { func output() { print(type(of:self))
        default.bar() // fallback an call directly the default
        implementation whenever needed self.bar() // will print "I am bar."
        on A().output() but should print "I am B." if Self == B (self as!
        B).bar() } } class B : A { override func bar() { print("I am B.") } } |

        I still think default implementations should be called through
        something like |default.| + whenever you override a default
        implementation you’d need |override|. There is a discussion going
        on: |Mark protocol methods with their protocol|. I clearly did not
        solved your issue, but I might have wake your interest to
        participate. :wink:

        --
        Adrian Zubarev
        Sent with Airmail

        Am 20. September 2016 um 04:13:22, Zhao Xin via swift-users
        (swift-users@swift.org <mailto:swift-users@swift.org>) schrieb:

        See below code.

        protocol Foo {

            func bar()

        }

        extension Foo {

            func bar() {

                print("I am bar.")

            }

        }

        class A:Foo {

            func output() {

                print(type(of:self)) // prints "B".

                self.bar() // prints "I am bar."

                (self as! B).bar() // prints "I am B."

            }

        }

        class B:A {

            func bar() {

                print("I am B.")

            }

        }

        let b = B()

        b.output()

        I thought `self.bar()` would do the same as `(self as! B).bar()`.
        It didn't. In my opinion, `type(of:self) is B.type`, so they
        should be the same, shouldn't they?

        Zhaoxin

        _______________________________________________
        swift-users mailing list
        swift-users@swift.org <mailto:swift-users@swift.org>
        https://lists.swift.org/mailman/listinfo/swift-users
        <https://lists.swift.org/mailman/listinfo/swift-users>

        _______________________________________________
        swift-evolution mailing list
        swift-evolution@swift.org <mailto:swift-evolution@swift.org>
        https://lists.swift.org/mailman/listinfo/swift-evolution
        <https://lists.swift.org/mailman/listinfo/swift-evolution>

    _______________________________________________
    swift-evolution mailing list
    swift-evolution@swift.org <mailto:swift-evolution@swift.org>
    https://lists.swift.org/mailman/listinfo/swift-evolution
    <https://lists.swift.org/mailman/listinfo/swift-evolution>

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Zhao Xin) #9

I am not sure why protocol extension need to differ so much and present

dispatch rules that are potentially very confusing.

I think that both the Java and Swift designers want to get the benefits
of multiple inherences, in the meaning time, they don't want to support
multiple objects inherence.

For Java only, as Java allows implicit override, the `@override` is
optional. Related bugs are hard to find if you don't use `@override`.

For me, the current rule is simple.
1. If there is a `override`, it is "class dynamic binding". If there is no
`override`, it is not. The dynamic type of `self` is irrelevant.
2. The method in 'protocol extension` is default, which means fail safe. It
is not a method of a class until the class implements it.

Zhaoxin

···

On Wed, Sep 21, 2016 at 4:10 AM, Goffredo Marocchi <panajev@gmail.com> wrote:

This would make for hilarious debugging session if you have the misfortune
of using a third party binary framework that gets updated and provide
default implementations for some methods in the protocol extensions.

When Java 8 also decided to blur the lines between classes
(implementations) and interfaces (equivalent of protocols on this side of
the fence more or less... anyways they represent behaviours/API contracts),
they also provided a very simple rule to determine on the code would behave
at runtime.

Extending Interfaces That Contain Default Methods

When you extend an interface that contains a default method, you can do
the following:

   - Not mention the default method at all, which lets your extended
   interface inherit the default method.
   - Redeclare the default method, which makes it abstract.
   - Redefine the default method, which overrides it.

https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html

I am not sure why protocol extension need to differ so much and present
dispatch rules that are potentially very confusing.

Casting at runtime should *never* change what implementation of a method
gets called.
For a safe by default language the fact that this can occur is quite
puzzling and worrying. I am not sure the cost of implementing the current
static/dynamic dispatch rules for default methods in protocol extensions is
worth it to say it bluntly, but please enlighten me if I am missing an
obvious huge pink elephant in the room here.

Sent from my iPhone

On 20 Sep 2016, at 16:18, Nevin Brackett-Rozinsky via swift-evolution < > swift-evolution@swift.org> wrote:

I think there is a deeper issue that may be worth exploring here.

Notably, when one class presents a member function, its subclasses ought
to use “override” when they reimplement that method themselves, regardless
of where the superclass’s version comes from.

In the original post, the class “A” expresses (by conforming to protocol
“Foo”) that it has a member function “bar()”, and “B” is a subclass of “A”
which wants its own definition of “bar()”.

It seems to me that “B” should not care whether “A” rolled its own
implementation of “bar()” or used the default implementation provided by
“Foo”.

From the perspective of “B”, its superclass “A” promises to have a member
function “bar()”, so “B” should need to use the `override` keyword just
like it would when overriding any other method.

To illustrate this more clearly, suppose that “Foo” and “A: Foo” are
defined in a 3rd-party library, while “B: A” is written in a client module.

If the library changes to give “A” its own custom implementation of
“bar()”, that *should not* affect client code—because the class “A” still
conforms to “Foo” so it still is known to have a “bar()” method—but right
now it *does*:

With the status quo, the simple change of moving a function between a
protocol extension and a conforming class currently requires downstream
source-code modifications in clients (in this case, adding `override` to
“B.bar()”).

I propose that `override` should be required in subclasses on any method
which the superclass proffers as a customization point, no matter the
provenance of that claim.

Nevin

On Tue, Sep 20, 2016 at 8:01 AM, Zhao Xin via swift-evolution < > swift-evolution@swift.org> wrote:

Thank you to Игорь Никитин and Adrian Zubarev. Now I can convince myself
for this behavior.

As Adrian's example shows, there is no `bar()` implemented in `class A`,
so there is no `override func bar()` in class B`. My thought that `self.bar()`
would do the same as `(self as! B).bar()`, is called "dynamic binding",
which is basing on the `override`. Since there is no `override`, there is
no "dynamic binding". I thought "dynamic binding" was basing on dynamic
type of `self`. It was not. I was wrong.

The behavior is clear now. In class A's `self.bar()`, the runtime finds
that there is no implementation of `bar()` in `class A`, so it calls the
`bar` in protocol extension. In class A's `(self as! B).bar()`, as `class
B` contains the implementation of `bar()`, the runtime calls it.

Zhaoxin

On Tue, Sep 20, 2016 at 4:21 PM, Adrian Zubarev via swift-evolution < >> swift-evolution@swift.org> wrote:

I can’t tell you the reason, but to me it feels like it’s doing the
following thing:

+ - - (Type: B) - - +
> >
> func bar() + - + (Type: A) - - + < - - - - - - - - - - - - - - - - - - - - +
> > > >
+ - - - - - - - + func output() + - + (Protocol: Foo) - - + — - self.bar() - + - (self as! B).bar() - +
                > > > >
                + - - - - - - - + (default) func bar() | <- - - - - - - - +
                                > >
                                + - - - - - - - - - - - - +

class A:Foo {

    func bar() {}

    func output() {
        print(type(of:self))
        self.bar()
        (self as! B).bar()
    }
}

class B:A {

    override func bar() {
        print("I am B.")
    }
}

Would solve this temporarily.

And there we are again with the same discussion if custom implementation
of protocol members, which have default implementation, should have the
override keyword or not.

Imagine your code like this (not valid code):

protocol Foo {
    func bar()
}

extension Foo {
    func bar() {
        print("I am bar.")
    }
}

class A : Foo {

    func output() {

        print(type(of:self))
        default.bar() // fallback an call directly the default implementation whenever needed
        self.bar() // will print "I am bar." on A().output() but should print "I am B." if Self == B
        (self as! B).bar()
    }
}

class B : A {

    override func bar() {
        print("I am B.")
    }
}

I still think default implementations should be called through something
like default. + whenever you override a default implementation you’d
need override. There is a discussion going on: Mark protocol methods
with their protocol. I clearly did not solved your issue, but I might
have wake your interest to participate. :wink:

--
Adrian Zubarev
Sent with Airmail

Am 20. September 2016 um 04:13:22, Zhao Xin via swift-users (
swift-users@swift.org) schrieb:

See below code.

protocol Foo {

    func bar()

}

extension Foo {

    func bar() {

        print("I am bar.")

    }

}

class A:Foo {

    func output() {

        print(type(of:self)) // prints "B".

        self.bar() // prints "I am bar."

        (self as! B).bar() // prints "I am B."

    }

}

class B:A {

    func bar() {

        print("I am B.")

    }

}

let b = B()

b.output()

I thought `self.bar()` would do the same as `(self as! B).bar()`. It
didn't. In my opinion, `type(of:self) is B.type`, so they should be the
same, shouldn't they?

Zhaoxin
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Goffredo Marocchi) #10

> I am not sure why protocol extension need to differ so much and present dispatch rules that are potentially very confusing.

I think that both the Java and Swift designers want to get the benefits of multiple inherences, in the meaning time, they don't want to support multiple objects inherence.

For Java only, as Java allows implicit override, the `@override` is optional. Related bugs are hard to find if you don't use `@override`.

For me, the current rule is simple.
1. If there is a `override`, it is "class dynamic binding". If there is no `override`, it is not. The dynamic type of `self` is irrelevant.
2. The method in 'protocol extension` is default, which means fail safe. It is not a method of a class until the class implements it.

Classic dynamic binding has its charms yes ;).

To be on point, once you adopt the protocol, and thus the extensions that may also have been declared and the default methods, and you decide to override or happen to override the default implementation it is still not enough to make sure you will call your implementation in your own code. If the reference to the instance of the class is cast to the protocol type, I want other object to be aware of my API contract not the specific class instance, then the protocol default method gets called and that is several shades of not appropriate for me.

https://nomothetis.svbtle.com/the-ghost-of-swift-bugs-future (with subclassing this can get more complicated)

Reasoning:
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001922.html

... hence why turning protocol dispatching into dynamic dispatching, unless the user says otherwise (@Kevin: sometimes it makes the language easier to use without sacrificing speed if we renounce a tad of purity and accept a dedicated keyword as compiler hint... a simple @static or something would suffice).
Updating a version of a binary framework could be covered in extra perils you do not need.

···

Sent from my iPhone

On 21 Sep 2016, at 01:41, Zhao Xin <owenzx@gmail.com> wrote:

Zhaoxin

On Wed, Sep 21, 2016 at 4:10 AM, Goffredo Marocchi <panajev@gmail.com> wrote:
This would make for hilarious debugging session if you have the misfortune of using a third party binary framework that gets updated and provide default implementations for some methods in the protocol extensions.

When Java 8 also decided to blur the lines between classes (implementations) and interfaces (equivalent of protocols on this side of the fence more or less... anyways they represent behaviours/API contracts), they also provided a very simple rule to determine on the code would behave at runtime.

Extending Interfaces That Contain Default Methods

When you extend an interface that contains a default method, you can do the following:

Not mention the default method at all, which lets your extended interface inherit the default method.
Redeclare the default method, which makes it abstract.
Redefine the default method, which overrides it.

https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html

I am not sure why protocol extension need to differ so much and present dispatch rules that are potentially very confusing.

Casting at runtime should *never* change what implementation of a method gets called.
For a safe by default language the fact that this can occur is quite puzzling and worrying. I am not sure the cost of implementing the current static/dynamic dispatch rules for default methods in protocol extensions is worth it to say it bluntly, but please enlighten me if I am missing an obvious huge pink elephant in the room here.

Sent from my iPhone

On 20 Sep 2016, at 16:18, Nevin Brackett-Rozinsky via swift-evolution <swift-evolution@swift.org> wrote:

I think there is a deeper issue that may be worth exploring here.

Notably, when one class presents a member function, its subclasses ought to use “override” when they reimplement that method themselves, regardless of where the superclass’s version comes from.

In the original post, the class “A” expresses (by conforming to protocol “Foo”) that it has a member function “bar()”, and “B” is a subclass of “A” which wants its own definition of “bar()”.

It seems to me that “B” should not care whether “A” rolled its own implementation of “bar()” or used the default implementation provided by “Foo”.

From the perspective of “B”, its superclass “A” promises to have a member function “bar()”, so “B” should need to use the `override` keyword just like it would when overriding any other method.

To illustrate this more clearly, suppose that “Foo” and “A: Foo” are defined in a 3rd-party library, while “B: A” is written in a client module.

If the library changes to give “A” its own custom implementation of “bar()”, that *should not* affect client code—because the class “A” still conforms to “Foo” so it still is known to have a “bar()” method—but right now it *does*:

With the status quo, the simple change of moving a function between a protocol extension and a conforming class currently requires downstream source-code modifications in clients (in this case, adding `override` to “B.bar()”).

I propose that `override` should be required in subclasses on any method which the superclass proffers as a customization point, no matter the provenance of that claim.

Nevin

On Tue, Sep 20, 2016 at 8:01 AM, Zhao Xin via swift-evolution <swift-evolution@swift.org> wrote:
Thank you to Игорь Никитин and Adrian Zubarev. Now I can convince myself for this behavior.

As Adrian's example shows, there is no `bar()` implemented in `class A`, so there is no `override func bar()` in class B`. My thought that `self.bar()` would do the same as `(self as! B).bar()`, is called "dynamic binding", which is basing on the `override`. Since there is no `override`, there is no "dynamic binding". I thought "dynamic binding" was basing on dynamic type of `self`. It was not. I was wrong.

The behavior is clear now. In class A's `self.bar()`, the runtime finds that there is no implementation of `bar()` in `class A`, so it calls the `bar` in protocol extension. In class A's `(self as! B).bar()`, as `class B` contains the implementation of `bar()`, the runtime calls it.

Zhaoxin

On Tue, Sep 20, 2016 at 4:21 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:
I can’t tell you the reason, but to me it feels like it’s doing the following thing:

+ - - (Type: B) - - +
> >
> func bar() + - + (Type: A) - - + < - - - - - - - - - - - - - - - - - - - - +
> > > >
+ - - - - - - - + func output() + - + (Protocol: Foo) - - + — - self.bar() - + - (self as! B).bar() - +
                > > > >
                + - - - - - - - + (default) func bar() | <- - - - - - - - +
                                > >
                                + - - - - - - - - - - - - +
class A:Foo {
     
    func bar() {}
     
    func output() {
        print(type(of:self))
        self.bar()
        (self as! B).bar()
    }
}

class B:A {

    override func bar() {
        print("I am B.")
    }
}
Would solve this temporarily.

And there we are again with the same discussion if custom implementation of protocol members, which have default implementation, should have the override keyword or not.

Imagine your code like this (not valid code):

protocol Foo {
    func bar()
}

extension Foo {
    func bar() {
        print("I am bar.")
    }
}

class A : Foo {
     
    func output() {
         
        print(type(of:self))
        default.bar() // fallback an call directly the default implementation whenever needed
        self.bar() // will print "I am bar." on A().output() but should print "I am B." if Self == B
        (self as! B).bar()
    }
}

class B : A {

    override func bar() {
        print("I am B.")
    }
}
I still think default implementations should be called through something like default. + whenever you override a default implementation you’d need override. There is a discussion going on: Mark protocol methods with their protocol. I clearly did not solved your issue, but I might have wake your interest to participate. :wink:

--
Adrian Zubarev
Sent with Airmail

Am 20. September 2016 um 04:13:22, Zhao Xin via swift-users (swift-users@swift.org) schrieb:

See below code.

protocol Foo {
    func bar()
}

extension Foo {
    func bar() {
        print("I am bar.")
    }
}

class A:Foo {
    func output() {
        print(type(of:self)) // prints "B".
        self.bar() // prints "I am bar."
        (self as! B).bar() // prints "I am B."
    }
}

class B:A {
    func bar() {
        print("I am B.")
    }
}

let b = B()
b.output()

I thought `self.bar()` would do the same as `(self as! B).bar()`. It didn't. In my opinion, `type(of:self) is B.type`, so they should be the same, shouldn't they?

Zhaoxin
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Vladimir) #11

Could you provide some example? I was not able to reproduce such behavior(and was not expected to be able):
(Probably, you want to mention helper methods in protocol extension that was not defined *in protocol itself*, then yes. But AFAIK not for the *default implementation* of protocol requirement i.e. the method/prop that *is* declared in "main" protocol definition)

protocol A {
     func foo()
}

extension A {
     func foo() { print("A") }
}

class C : A {
     func foo() { print("C") }
}

let a : A = C()
a.foo() // "C"

func f(a: A) {
     a.foo()
}
f(a: a) // "C"

func g<T>(a: T) where T : A {
     a.foo()
}
g(a: C()) // "C"

func h<T: Sequence>(a: T) where T.Iterator.Element : A {
     for e in a {
         e.foo()
     }
}
h(a: [C()]) // "C"

func i<T: Sequence>(a: T) where T.Iterator.Element == A {
     for e in a {
         e.foo()
     }
}
i(a: [a]) // "C"

···

On 21.09.2016 9:30, Goffredo Marocchi via swift-evolution wrote:

If the reference to the instance of the class is cast to the protocol type,
I want other object to be aware of my API contract not the specific class
instance, then the protocol default method gets called and that is several
shades of not appropriate for me.