Sent from my iPad
> On Dec 10, 2017, at 4:30 PM, Jens Persson <j...@bitcycle.com> 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. Oh, that’s awesome! I didn’t know this works in the latest snapshots. I’m really happy to know this works now. > > > /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