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

Reply via email to