Oh btw Matthew, you wouldn't consider https://bugs.swift.org/browse/SR-6564 a bug then?
/Jens On Sun, Dec 10, 2017 at 11:30 PM, Jens Persson via swift-users < swift-users@swift.org> wrote: > 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 > >
_______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users