[swift-users] Swift's method dispatch

Jens Persson jens at bitcycle.com
Sun Dec 10 15:40:59 CST 2017


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 {
    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?

let y = Y(a: X<Int>())
y.g() // What will this print?

If anyone knows for sure what this program will print (without having to
run it), please enlighten me!

/Jens


On Sat, Dec 9, 2017 at 1:54 AM, Jordan Rose <jordan_rose at 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 at 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 <gparker at 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 at 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 at 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 at swift.org
>> >> https://lists.swift.org/mailman/listinfo/swift-users
>> >
>> > _______________________________________________
>> > swift-users mailing list
>> > swift-users at swift.org
>> > https://lists.swift.org/mailman/listinfo/swift-users
>>
>>
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20171210/774437de/attachment.html>


More information about the swift-users mailing list