[swift-evolution] [Proposal draft] Conditional conformances

Dave Abrahams dabrahams at apple.com
Fri Sep 30 22:18:26 CDT 2016


on Fri Sep 30 2016, Matthew Johnson <swift-evolution at swift.org> wrote:

>> It’s a valid concern, and I’m sure it does come up in practice. Let’s create a small, self-contained example:
>> 
>> protocol P {
>>   func f()
>> }
>> 
>> protocol Q: P { }
>> 
>> struct X<T> { let t: T}
>> 
>> extension X: P where T: P {
>>   func f() {
>>     /* general but slow */
>>   }
>> }
>> 
>> extension X where T: Q {
>>   func f() {
>>     /* fast because it takes advantage of T: Q */
>>   }
>> }
>> 
>> struct IsQ : Q { }
>> 
>> func generic<U: P>(_ value: u) {
>>   value.f()
>> }
>> 
>> generic(X<IsQ>())
>> 
>> We’d like for the call to “value.f()” to get the fast version of f()
>> from the second extension, but the proposal doesn’t do that: the
>> conformance to P is “locked in” to the first extension.

I suppose that's true even if the second extension introduces X : Q?

>> If we assume that we can see all of the potential implementations of
>> “f” to which we might want to dispatch, we could implement some
>> dynamic scheme that tries to pick the most specialized one. Of
>> course, as with overlapping conformances in general, this selection
>> process could result in ambiguities.
>
> This is what I suspected.  I’ll defer to Dave A on how big a concern
> this is, but it seems to me like a bit of a slippery slope towards
> sub-optimal performance.

Well, it's unfortunate.  We have a similar problem today due to the lack
of conditional conformance, and we deal with it by injecting an
underscored requirement where it doesn't belong, then dispatch through
that.  I wonder if the workaround for this limitation is like that, or
something completely different.

Does this work?  If not, why not?  If so, what makes it fundamentally
different, since it is trying to express the same thing through
different means?

-----

public protocol P {
  func f()
}

public protocol Q: P { }

public struct X<T> { let t: T}

internal protocol XFImpl {
  associatedtype TT: P
  static func f(X<T>)
}

extension XFImpl {
 static func f(X<TT>) { /* general but slow */ }
}

extension XFImpl where TT: Q {
  static func f(X<TT>) { /* fast because it takes advantage of T: Q */ }
}

extension X: P where T: P {
  struct FImpl : XFImpl {
    typealias TT = T
  }

  func f() {
    FImpl.f(self)
  }
}

struct IsQ : Q { }

func generic<U: P>(_ value: u) {
  value.f()
}

generic(X<IsQ>())

-- 
-Dave



More information about the swift-evolution mailing list