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 > <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 > <mailto: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 <mailto: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 <mailto: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 <mailto:swift-users@swift.org> > >> https://lists.swift.org/mailman/listinfo/swift-users > >> <https://lists.swift.org/mailman/listinfo/swift-users> > > > > _______________________________________________ > > 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-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