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

Reply via email to