[swift-users] Swift's method dispatch

Jens Persson jens at bitcycle.com
Sun Dec 10 16:32:42 CST 2017


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 at 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 <matthew at anandabits.com>
> wrote:
>
>>
>>
>> Sent from my iPad
>>
>> On Dec 10, 2017, at 3:41 PM, Jens Persson via swift-users <
>> swift-users at 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_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
>>>
>>>
>>>
>> _______________________________________________
>> 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/2fc0ecf3/attachment.html>


More information about the swift-users mailing list