Thank you Matthew, I will try to digest and incorporate your explanation. I'm using a recent snapshot where struct X<T> : P { func f() { print("this one is actually best") } } compiles fine without requiring that type alias.
/Jens On Sun, Dec 10, 2017 at 10:52 PM, Matthew Johnson <matt...@anandabits.com> wrote: > > > 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