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 > <[email protected]> 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 >> <[email protected]> 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 >>> <[email protected]> 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. ;) >>> >>> >>> >>> -- >>> Adrian Zubarev >>> Sent with Airmail >>> >>> Am 20. September 2016 um 04:13:22, Zhao Xin via swift-users >>> ([email protected]) 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 >>>> [email protected] >>>> https://lists.swift.org/mailman/listinfo/swift-users >>> >>> >>> _______________________________________________ >>> swift-evolution mailing list >>> [email protected] >>> https://lists.swift.org/mailman/listinfo/swift-evolution >>> >> >> >> _______________________________________________ >> swift-evolution mailing list >> [email protected] >> https://lists.swift.org/mailman/listinfo/swift-evolution >> > > _______________________________________________ > swift-evolution mailing list > [email protected] > https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
