Sent from my iPad
> On Dec 10, 2017, at 3:41 PM, Jens Persson via swift-users > <swift-users@swift.org> wrote: > > I'm trying to get my head around the current behavior, but its very hard to > understand and remember, and judging by the comments here and on my bug > report (SR-6564), so does even people in the core team. It would be nice if > someone could present a complete set of rules (all the ones I've seen are far > to simplified and does not cover all cases). > Here's another example to consider: > > protocol P { > associatedtype T > func f() // * > } > extension P { > func f() { print("T is unknown") } > } > extension P where T == Int { > func f() { print("T is Int") } > } > > struct X<T> : P { FWIW, this does not compile. You need to provide a typealias for T which you can’t do when the generic parameter is named T. > func f() { print("this one is actually best") } > } > extension X where T == Int { > func f() { print("this one is actually better than best.") } > } > > struct Y<U> where U: P, U.T == Int { > typealias T = U.T > var a: U > func g() { a.f() } > } > > let x = X<Int>() > x.f() // What will this print? This prints “this one is actually better than best.” because the method is invoked on a concrete type. Overload resolution is used to identify the most specific implementation which in this case is the method in the concrete extension on X. > > let y = Y(a: X<Int>()) > y.g() // What will this print? This prints ”this one is actually best”. This is because the method is called in a generic context and is a protocol requirement. This means it is dispatched through the protocol witness table. The methods in the extensions on P are default implementations which are disregarded because X provides its own implementation. The overload in the extension on X is not visible at all in a generic context because it does not participate in X’s conformance to P. > > If anyone knows for sure what this program will print (without having to run > it), please enlighten me! I hope the above helps. If you have further questions please ask! > > /Jens > > >> On Sat, Dec 9, 2017 at 1:54 AM, Jordan Rose <jordan_r...@apple.com> wrote: >> Consider this example: >> >> protocol P { >> associatedtype T >> func f() // * >> } >> extension P { >> func f() { print("T is unknown") } >> } >> extension P where T == Int { >> func f() { print("T is Int") } >> } >> >> struct X<T> : P { >> func f() { print("this one is actually best") } >> } >> >> struct Y<U> where U: P, U.T == Int { >> typealias T = U.T >> var a: U >> func g() { a.f() } >> } >> >> let x = X<Int>() >> x.f() // "this one is actually best" >> >> let y = Y(a: X<Int>()) >> y.g() // "this one is actually best" >> >> I can't think of any other choice for 'a.f()' that would preserve this >> behavior, which means we're doing the best thing: prefer dynamic dispatch >> over static dispatch when operating on a generic value. (Or at least the >> "least bad" thing.) And of course this reasoning has to be local; Y.g can't >> look and say "oh, I know nothing else conforms to P, and X {does, doesn't} >> have a custom implementation, so I should pick the constrained extension >> instead". >> >> The real answer might be "we should have had a different syntax for default >> implementations vs. mixin operations", but that's a much bigger can of worms. >> >> Jordan >> >> >>> On Dec 8, 2017, at 13:07, Jens Persson via swift-users >>> <swift-users@swift.org> wrote: >>> >>> Thanks Slava and Greg, >>> >>> ( >>> I'm aware that it prints "T is Int" from both calls if I remove func f() >>> from P itself, that's why I wrote "... unless * is commented out." in the >>> comment of the last line >>> Note that the "U.T == Int"-part of >>> struct Y<U> where U: P, U.T == Int { >>> is key here. If it had been only >>> struct Y<U> where U: P { >>> then I hadn't been surprised that it printed "T is unknown". >>> ) >>> >>> Filed https://bugs.swift.org/browse/SR-6564 since I think it is just >>> strange that the compiler should not use its knowledge of U.T == Int when >>> choosing between the two f()-implementations. >>> I think I will be a little disappointed if the solution is to deem it an >>> ambiguity >>> : ) >>> >>> /Jens >>> >>> >>> >>>> On Fri, Dec 8, 2017 at 9:19 PM, Greg Parker <gpar...@apple.com> wrote: >>>> Evidence in favor of Slava's analysis: if you remove `func f()` from P >>>> itself, leaving it in the extensions only, then you get "T is Int" from >>>> both calls. >>>> >>>> >>>> > On Dec 8, 2017, at 12:12 PM, Slava Pestov via swift-users >>>> > <swift-users@swift.org> wrote: >>>> > >>>> > Hi Jens, >>>> > >>>> > I think the problem is that overload ranking always prefers a protocol >>>> > requirement to a protocol extension member, because usually you want the >>>> > dynamic dispatch through the requirement instead of calling the default >>>> > implementation. But it appears that this heuristic does not take into >>>> > account the fact that the protocol extension member could be more >>>> > constrained than the requirement. >>>> > >>>> > Please file a bug, but it is unclear what the desired behavior actually >>>> > is here. Perhaps it should just diagnose an ambiguity. >>>> > >>>> > Slava >>>> > >>>> >> On Dec 8, 2017, at 6:25 AM, Jens Persson via swift-users >>>> >> <swift-users@swift.org> wrote: >>>> >> >>>> >> Hi all! >>>> >> >>>> >> Can someone please explain the rationale behind the last line printing >>>> >> "T is unknown" >>>> >> rather than (what I would expect): >>>> >> "T is Int" >>>> >> in the following program? >>>> >> >>>> >> >>>> >> protocol P { >>>> >> associatedtype T >>>> >> func f() // * >>>> >> } >>>> >> extension P { >>>> >> func f() { print("T is unknown") } >>>> >> } >>>> >> extension P where T == Int { >>>> >> func f() { print("T is Int") } >>>> >> } >>>> >> >>>> >> struct X<T> : P {} >>>> >> >>>> >> struct Y<U> where U: P, U.T == Int { >>>> >> // NOTE: The compiler/type-checker knows that U.T == Int here so ... >>>> >> typealias T = U.T >>>> >> var a: U >>>> >> func g() { a.f() } // ... how/why could this print anything but "T >>>> >> is Int"? >>>> >> } >>>> >> >>>> >> let x = X<Int>() >>>> >> x.f() // Prints "T is Int", no matter if * is commented out or not. >>>> >> >>>> >> let y = Y(a: X<Int>()) >>>> >> y.g() // Prints "T is unknown" unless * is commented out. Why? >>>> >> >>>> >> >>>> >> IMHO this looks like the compiler simply ignores that struct Y<U> has >>>> >> the constraint U.T == Int. >>>> >> How else to explain this behavior? >>>> >> /Jens >>>> >> >>>> >> _______________________________________________ >>>> >> swift-users mailing list >>>> >> swift-users@swift.org >>>> >> https://lists.swift.org/mailman/listinfo/swift-users >>>> > >>>> > _______________________________________________ >>>> > swift-users mailing list >>>> > swift-users@swift.org >>>> > https://lists.swift.org/mailman/listinfo/swift-users >>>> >>> >>> _______________________________________________ >>> swift-users mailing list >>> swift-users@swift.org >>> https://lists.swift.org/mailman/listinfo/swift-users >> > > _______________________________________________ > swift-users mailing list > swift-users@swift.org > https://lists.swift.org/mailman/listinfo/swift-users
_______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users