Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-10-03 Thread Joe Groff via swift-evolution

> On Oct 2, 2016, at 8:56 AM, Callionica (Swift) via swift-evolution 
>  wrote:
> 
> Interesting comment about worries that you'd be dispatched to the least good 
> SS version . A different language with different constraints, but when LINQ 
> to Objects implementers needed to provide optimized c# implementations for 
> some operations they chose a runtime type check to dispatch to the optimized 
> version. For example, while API is exposed as IEnumerable there are method 
> implementations that check for ICollection at runtime in order to hit more 
> efficient implementations. So static dispatch is good, but win for 
> collections often big enough to overcome a hit from dynamic dispatch. 

Yep, and Swift's specialization optimization already knows how to fold `is` and 
`as` checks after specializing a generic, so checking for a specific type or 
sub-protocol and jumping into a more optimized implementation for that subtype 
"dynamically" is still likely to be optimized away.

-Joe

> On Sunday, October 2, 2016, plx via swift-evolution 
> > wrote:
> 
>> On Sep 30, 2016, at 1:23 PM, Douglas Gregor > > wrote:
>>> 
>>> This is purely anecdotal but I had a lot of utility code laying around that 
>>> I’d marked with notes like `// TODO: revisit once conditional conformances 
>>> are available`.
>>> 
>>> When I was leaving those notes I was expecting to need overlapping 
>>> conformances often, but I reviewed them *before* replying and I actually 
>>> haven’t found an example where having overlapping conformances is both (1) 
>>> a significant win and also (2) a win in a way that’d be of broad, general 
>>> interest.
>>> 
>>> - 80% have no real need for overlapping conditional conformances
>>> - 15% might have “elegance gains” but nothing practically-significant
>>> - 5% would *probably* see real gains but are likely not of broad interest
>>> 
>>> …which wasn’t what I was expecting, but leaves me a lot more comfortable 
>>> without overlapping conformances for now than I was in the abstract.
>> 
>> Very interesting, thanks for doing this review!
> 
> I've taken the time to provide a bit more color on the 80/15/5 breakdown 
> because I don't see much discussion for this proposal in terms of concrete 
> situations...just theoretical concerns and theoretical possibilities. I don't 
> have any completed code either, but I have notes and to-do lists for things I 
> was planning to do, and I think seeing even some semi-concrete scenarios 
> might be helpful here.
> 
> The "80%" are generally analogous to the `SomeWrapper` in the writeup; as a 
> concrete example, I was waiting on the availability of conditional 
> conformances to resume work on an emulation of structural unions, e.g. 
> something like:
> 
>   enum Sum2 {
> case a(A)
> case b(B)
>   }
>   
> ...(and analogously for 3, 4, as-necessary). 
> 
> There's a very obvious way to write `extension Sum2 : Equatable where 
> A:Equatable, B:Equatable {}`...and at the time I set this aside, I was 
> expecting to also want to come back and have additional conformances for 
> things like `...where A:Equatable, B:AnyObject` (using `===` for comparing 
> `B`) and so on for other combinations.
> 
> Upon revisiting such things in light of the proposal, I now think 
> differently: for this case it seems like a better long-term approach anyways 
> to stick to a single conformance and work with it like this:
> 
>   extension Sum2:Equatable where A:Equatable, B:Equatable {
> // details elided
>   }
>   
>   /// Adaptor using `ObjectIdentifier` to implement `==`.
>   struct ObjectWrapper : Equatable, Hashable {
> let wrapped: Wrapped
>   }
>   
> ...as upon reflection I really would prefer dealing with the hassle of 
> working with `Sum2` in situations where -- in theory -- 
> `Sum2` could do -- to the hassle of writing out 4+ conformances for 
> `Sum2` (and so on...even with nice code-gen tools that's going to be a lot of 
> bloat!). 
> 
> What changed my mind was tracing through the implications of conditional 
> conformances for the use-site ergonomics of adaptors like `ObjectWrapper` 
> above; what I mean is, suppose I have a protocol like this:
> 
>   protocol WidgetFactory {
> associatedtype Widget
> associatedtype Material
> 
> func produceWidget(using material: Material) -> Widget
>   }
> 
> ...then it's rather easy to simply write this type of boilerplate:
> 
>   extension ObjectWrapper: WidgetFactory where Wrapped: WidgetFactory {
> typealias Widget = Wrapper.Widget
> typealias Material = Wrapper.Material
> 
> func produceWidget(using material: Material) -> Widget {
>   return base.produceWidget(using: material)
> }
>   }
>   
> ...which thus means I have the tools I need to make my use of wrappers like 
> the `ObjectWrapper` 

Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-10-03 Thread Dave Abrahams via swift-evolution

on Mon Oct 03 2016, Alexis  wrote:

> Below I’ve provided a more fleshed out version of what Dave is
> suggesting, for anyone who had trouble parsing the very hypothetical
> example. It reflects the kind of implementation specialization I would
> expect to see in the standard library. 

Thanks, Alexis.

Doug and I talked this morning and fortunately I think we came up with
something rational that will support the kind of specialization we want
without any hoop-jumping.  It basically involves precomputing the
overload lattice and filling witness tables dynamically based on the
conformances that are statically visible at the moment they are
instantiated.  We'll post more detail soon.

-- 
-Dave
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-10-03 Thread Alexis via swift-evolution
Below I’ve provided a more fleshed out version of what Dave is suggesting, for 
anyone who had trouble parsing the very hypothetical example. It reflects the 
kind of implementation specialization I would expect to see in the standard 
library. In fact we have exactly this concern baked into value witness tables 
today by differentiating the various *Buffer methods so that they can be no-ops 
or memcpys for trivial values (rather than requiring code to loop over all the 
elements and call potentially-no-op methods on each element).

But the value witness table’s approach to this problem suggests some healthier 
solutions to the problem (for Swift’s particular set of constraints):

1) Add default-implemented fullAlgorithm() methods to the protocol. Anyone who 
can beat the default algorithm provides their own implementation. Consumers of 
the protocol then dispatch to fullAlgorithm(), rather than the lower-level 
primitives.

2) Add “let hasInterestingProperty: bool” flags to the protocol. Consumers of 
the protocol can then branch on these flags to choose a “slow generic” or “fast 
specific” implementation. (this is, after all, exactly what we’re asking the 
runtime to do for us!)

Of course, (1) and (2) aren’t always applicable solutions. Both only really 
apply if you’re the original creator of the protocol; otherwise no one will 
know about fullAlgorithm or hasInterestingProperty and be able to modify the 
default. It can also be really tedious to provide your own implementation of 
fullAlgorithm(), especially if everyone overloads it in the same way. These 
are, however, perfectly reasonable approaches if you’re just trying to 
specialize for a small, closed, set of types. Something like:

genericImpl()
stringImpl()
intImpl()

You can handle that pretty easily with extensions or super-protocols, I think.

I’m cautiously optimistic we can get pretty far before we really feel the need 
to introduce specialization like this. Although I’m used to handling this issue 
in a world of monomorphic generics; so I’m not sure if the performance 
characteristics of polymorphic generics will shift the balance to making 
specialization more urgent. Or perhaps the opposite — the runtime impact of 
specialization could be too high!


// Some kind of "super copy" operation
public protocol Clone {
  func clone() -> Self
}

// Can just memcpy instead of calling Clone
public protocol TrivialClone: Clone { }

// A terrible data structure
public struct FakeArray { let vals: (T, T, T) }



// --
// A dirty hack to get overlapping impls (specifically specialization)
// through overlapping extensions.

internal protocol CloneImpl {
  associatedtype TT: Clone
}

extension CloneImpl {
  static func clone(input: FakeArray) -> FakeArray {
// Have to manually invoke generic `clone` on each element
FakeArray(vals: (input.vals.0.clone(),
 input.vals.1.clone(),
 input.vals.2.clone()))
  }
}

extension CloneImpl where TT: TrivialClone {
  static func clone(input: FakeArray) -> FakeArray {
// Can just copy the whole buffer at once (ideally a memcpy)
FakeArray(vals: input.vals)
  }
}


// Inject our specialized Clone impl
// (doesn't compile today because this is a conditional conformance)
extension FakeArray: Clone where T: Clone {
  // A dummy to get our overlapping extensions
  // (doesn't compile today because we can't nest types in a generic type)
  struct CloneImplProvider : CloneImpl {
typealias TT = T
  }
  
  func clone() -> FakeArray {
CloneImplProvider.clone(input: self)
  }
}

// -
// Using Clone and the specialization

// Some plain-old-data
struct POD : TrivialClone {
  func clone() -> POD { return self }
}

// Works with any Clone type
func generic(_ value: T) -> T {
  return value.clone()
}

// Pass in a FakeArray that should use the fast specialization for Clone
generic(FakeArray(vals: (POD(), POD(), POD(




> On Sep 30, 2016, at 11:18 PM, Dave Abrahams via swift-evolution 
>  wrote:
> 
> 
> on Fri Sep 30 2016, Matthew Johnson  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 { 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(_ value: u) {
>>>  value.f()
>>> }
>>> 
>>> generic(X())
>>> 
>>> 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 

Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-10-02 Thread Callionica (Swift) via swift-evolution
Interesting comment about worries that you'd be dispatched to the least
good SS version . A different language with different constraints, but when
LINQ to Objects implementers needed to provide optimized c# implementations
for some operations they chose a runtime type check to dispatch to the
optimized version. For example, while API is exposed as IEnumerable
there are method implementations that check for ICollection at runtime
in order to hit more efficient implementations. So static dispatch is good,
but win for collections often big enough to overcome a hit from dynamic
dispatch.

On Sunday, October 2, 2016, plx via swift-evolution <
swift-evolution@swift.org> wrote:

>
> On Sep 30, 2016, at 1:23 PM, Douglas Gregor  > wrote:
>
>
> This is purely anecdotal but I had a lot of utility code laying around
> that I’d marked with notes like `// TODO: revisit once conditional
> conformances are available`.
>
> When I was leaving those notes I was expecting to need overlapping
> conformances often, but I reviewed them *before* replying and I actually
> haven’t found an example where having overlapping conformances is both (1)
> a significant win and also (2) a win in a way that’d be of broad, general
> interest.
>
> - 80% have no real need for overlapping conditional conformances
> - 15% might have “elegance gains” but nothing practically-significant
> - 5% would *probably* see real gains but are likely not of broad interest
>
> …which wasn’t what I was expecting, but leaves me a lot more comfortable
> without overlapping conformances for now than I was in the abstract.
>
>
> Very interesting, thanks for doing this review!
>
>
> I've taken the time to provide a bit more color on the 80/15/5 breakdown
> because I don't see much discussion for this proposal in terms of concrete
> situations...just theoretical concerns and theoretical possibilities. I
> don't have any completed code either, but I have notes and to-do lists for
> things I was planning to do, and I think seeing even some semi-concrete
> scenarios might be helpful here.
>
> The "80%" are generally analogous to the `SomeWrapper` in the writeup; as
> a concrete example, I was waiting on the availability of conditional
> conformances to resume work on an emulation of structural unions, e.g.
> something like:
>
>   enum Sum2 {
> case a(A)
> case b(B)
>   }
>
> ...(and analogously for 3, 4, as-necessary).
>
> There's a very obvious way to write `extension Sum2 : Equatable where
> A:Equatable, B:Equatable {}`...and at the time I set this aside, I was
> expecting to also want to come back and have additional conformances for
> things like `...where A:Equatable, B:AnyObject` (using `===` for comparing
> `B`) and so on for other combinations.
>
> Upon revisiting such things in light of the proposal, I now think
> differently: for this case it seems like a better long-term approach
> anyways to stick to a single conformance and work with it like this:
>
>   extension Sum2:Equatable where A:Equatable, B:Equatable {
> // details elided
>   }
>
>   /// Adaptor using `ObjectIdentifier` to implement `==`.
>   struct ObjectWrapper : Equatable, Hashable {
> let wrapped: Wrapped
>   }
>
> ...as upon reflection I really would prefer dealing with the hassle of
> working with `Sum2` in situations where -- in theory --
> `Sum2` could do -- to the hassle of writing out 4+ conformances for
> `Sum2` (and so on...even with nice code-gen tools that's going to be a lot
> of bloat!).
>
> What changed my mind was tracing through the implications of conditional
> conformances for the use-site ergonomics of adaptors like `ObjectWrapper`
> above; what I mean is, suppose I have a protocol like this:
>
>   protocol WidgetFactory {
> associatedtype Widget
> associatedtype Material
>
> func produceWidget(using material: Material) -> Widget
>   }
>
> ...then it's rather easy to simply write this type of boilerplate:
>
>   extension ObjectWrapper: WidgetFactory where Wrapped: WidgetFactory {
> typealias Widget = Wrapper.Widget
> typealias Material = Wrapper.Material
>
> func produceWidget(using material: Material) -> Widget {
>   return base.produceWidget(using: material)
> }
>   }
>
> ...which thus means I have the tools I need to make my use of wrappers
> like the `ObjectWrapper` largely transparent at the use sites I care about;
> e.g. I can write a single conditional conformance like this:
>
>   extension Sum2: WidgetFactory
> where
> A:WidgetFactory, B:WidgetFactory,
> A.Material == B.Material,
> A.Widget == B.Widget {
>
> typealias Widget = A.Widget
> typealias Material = A.Material
>
> func produceWidget(using material: Material) throws -> Widget {
>   switch self {
> case let .a(aa): return aa.produceWidget(using: material)
> case let .b(bb): return bb.produceWidget(using: material)
> 

Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-10-02 Thread plx via swift-evolution

> On Sep 30, 2016, at 1:23 PM, Douglas Gregor  wrote:
>> 
>> This is purely anecdotal but I had a lot of utility code laying around that 
>> I’d marked with notes like `// TODO: revisit once conditional conformances 
>> are available`.
>> 
>> When I was leaving those notes I was expecting to need overlapping 
>> conformances often, but I reviewed them *before* replying and I actually 
>> haven’t found an example where having overlapping conformances is both (1) a 
>> significant win and also (2) a win in a way that’d be of broad, general 
>> interest.
>> 
>> - 80% have no real need for overlapping conditional conformances
>> - 15% might have “elegance gains” but nothing practically-significant
>> - 5% would *probably* see real gains but are likely not of broad interest
>> 
>> …which wasn’t what I was expecting, but leaves me a lot more comfortable 
>> without overlapping conformances for now than I was in the abstract.
> 
> Very interesting, thanks for doing this review!

I've taken the time to provide a bit more color on the 80/15/5 breakdown 
because I don't see much discussion for this proposal in terms of concrete 
situations...just theoretical concerns and theoretical possibilities. I don't 
have any completed code either, but I have notes and to-do lists for things I 
was planning to do, and I think seeing even some semi-concrete scenarios might 
be helpful here.

The "80%" are generally analogous to the `SomeWrapper` in the writeup; as a 
concrete example, I was waiting on the availability of conditional conformances 
to resume work on an emulation of structural unions, e.g. something like:

  enum Sum2 {
case a(A)
case b(B)
  }
  
...(and analogously for 3, 4, as-necessary). 

There's a very obvious way to write `extension Sum2 : Equatable where 
A:Equatable, B:Equatable {}`...and at the time I set this aside, I was 
expecting to also want to come back and have additional conformances for things 
like `...where A:Equatable, B:AnyObject` (using `===` for comparing `B`) and so 
on for other combinations.

Upon revisiting such things in light of the proposal, I now think differently: 
for this case it seems like a better long-term approach anyways to stick to a 
single conformance and work with it like this:

  extension Sum2:Equatable where A:Equatable, B:Equatable {
// details elided
  }
  
  /// Adaptor using `ObjectIdentifier` to implement `==`.
  struct ObjectWrapper : Equatable, Hashable {
let wrapped: Wrapped
  }
  
...as upon reflection I really would prefer dealing with the hassle of working 
with `Sum2` in situations where -- in theory -- `Sum2` 
could do -- to the hassle of writing out 4+ conformances for `Sum2` (and so 
on...even with nice code-gen tools that's going to be a lot of bloat!). 

What changed my mind was tracing through the implications of conditional 
conformances for the use-site ergonomics of adaptors like `ObjectWrapper` 
above; what I mean is, suppose I have a protocol like this:

  protocol WidgetFactory {
associatedtype Widget
associatedtype Material

func produceWidget(using material: Material) -> Widget
  }

...then it's rather easy to simply write this type of boilerplate:

  extension ObjectWrapper: WidgetFactory where Wrapped: WidgetFactory {
typealias Widget = Wrapper.Widget
typealias Material = Wrapper.Material

func produceWidget(using material: Material) -> Widget {
  return base.produceWidget(using: material)
}
  }
  
...which thus means I have the tools I need to make my use of wrappers like the 
`ObjectWrapper` largely transparent at the use sites I care about; e.g. I can 
write a single conditional conformance like this:

  extension Sum2: WidgetFactory 
where 
A:WidgetFactory, B:WidgetFactory,
A.Material == B.Material,
A.Widget == B.Widget {

typealias Widget = A.Widget
typealias Material = A.Material

func produceWidget(using material: Material) throws -> Widget {
  switch self {
case let .a(aa): return aa.produceWidget(using: material)
case let .b(bb): return bb.produceWidget(using: material)
  }
}

  }
  
...and it will apply even in situations where circumstances left me using 
`ObjectWrapper` (or similar) on any of the type parameters to `Sum2` (e.g. if I 
also needed an `Equatable` conformance for whatever reason).

At least for now--when I'm still just revisiting plans and thinking about it in 
light of the proposal--I really would prefer having a simpler language and 
writing this type of boilerplate, than having a more-complex language and 
writing the *other* type of boilerplate (e.g. the 4+ `Equatable` conformances 
here, and so on for other situations).

Note that I'm not claiming the above is the only use for overlapping 
conditional conformances -- not at all! -- just that situations like the above 
comprise about 80% of the things I was intending to do with conditional 

Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-30 Thread Dave Abrahams via swift-evolution

on Fri Sep 30 2016, Matthew Johnson  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 { 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(_ value: u) {
>>   value.f()
>> }
>> 
>> generic(X())
>> 
>> 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 { let t: T}

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

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

extension XFImpl where TT: Q {
  static func f(X) { /* 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(_ value: u) {
  value.f()
}

generic(X())

-- 
-Dave

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-30 Thread Douglas Gregor via swift-evolution

> On Sep 30, 2016, at 6:25 AM, plx via swift-evolution 
>  wrote:
> 
> 
>> On Sep 28, 2016, at 5:53 PM, Douglas Gregor > > wrote:
>> 
>> 
>>> On Sep 28, 2016, at 1:28 PM, plx via swift-evolution 
>>> > wrote:
>>> 
>>> It’s good to see this starting to happen!
>>> 
>>> Is the decision on "no-overlapping-conformances” something that’s seen-as 
>>> set in stone permanently, set in stone for the near future, or perhaps at 
>>> least somewhat open to reconsideration at the present moment?
>> 
>> There hasn’t been a decision per se, so it that sense it’s open to 
>> reconsideration.
> 
> I see. A related question: if overlapping conditional conformances are 
> disallowed in Swift 4, would e.g. ABI concerns make it infeasible to relax 
> that restriction in future Swift (5, 6, X, etc.)?

It’s hard to be definitive without having a specific design for what 
overlapping conditional conformances would mean, but I feel fairly confident 
that we could introduce them later in some form. It would almost certainly 
involve deployment limitations—one would not be able to dynamically query for 
an overlapping conformance and have that code run correctly on a Swift 4 
runtime—but the general scheme in the ABI should generalize. 

> 
>> I have a strong *personal* bias against overlapping conformances, because I 
>> feel that the amount of complexity that they introduce into the language and 
>> its implementation far outweigh any benefits. Additionally, they enable use 
>> cases (e.g., static metaprogramming-ish tricks) that I feel would be 
>> actively harmful to the Swift language’s understandability. Generics systems 
>> can get very complicated very quickly, so any extension needs to be strongly 
>> motivated by use cases to matter to all or most Swift developers.
> 
> This is purely anecdotal but I had a lot of utility code laying around that 
> I’d marked with notes like `// TODO: revisit once conditional conformances 
> are available`.
> 
> When I was leaving those notes I was expecting to need overlapping 
> conformances often, but I reviewed them *before* replying and I actually 
> haven’t found an example where having overlapping conformances is both (1) a 
> significant win and also (2) a win in a way that’d be of broad, general 
> interest.
> 
> - 80% have no real need for overlapping conditional conformances
> - 15% might have “elegance gains” but nothing practically-significant
> - 5% would *probably* see real gains but are likely not of broad interest
> 
> …which wasn’t what I was expecting, but leaves me a lot more comfortable 
> without overlapping conformances for now than I was in the abstract.

Very interesting, thanks for doing this review!

- Doug

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-30 Thread Matthew Johnson via swift-evolution

> On Sep 30, 2016, at 1:23 AM, Douglas Gregor  wrote:
> 
> 
>> On Sep 28, 2016, at 4:30 PM, Matthew Johnson > > wrote:
>> 
 Is the decision on "no-overlapping-conformances” something that’s seen-as 
 set in stone permanently, set in stone for the near future, or perhaps at 
 least somewhat open to reconsideration at the present moment?
>>> 
>>> There hasn’t been a decision per se, so it that sense it’s open to 
>>> reconsideration.
>>> 
>>> I have a strong *personal* bias against overlapping conformances, because I 
>>> feel that the amount of complexity that they introduce into the language 
>>> and its implementation far outweigh any benefits.
>> 
>> I would like a bit further clarification on what the prohibition of 
>> overlapping conformances implies.
> 
> I think I presented it poorly in the proposal, and will see if I can find a 
> clearer exposition (for posterity, if not soon enough to aid the review).
> 
>>  For example, consider this modification of your example in a Swift that 
>> allows for same type constraints in extensions.  Would this be allowed?
> 
> Short answer: no. Longer answer below.
> 
>>  There would be two different conformances to Foo for SomeWrapper, but they 
>> would never “overlap” (i.e. both be candidates for the same concrete type).
>> struct SomeWrapper {
>>   let wrapped: Wrapped
>> }
>> 
>> protocol Foo {
>> associatedtype Bar
>>   func bar() -> Bar
>> }
>> 
>> extension SomeWrapper: Foo where Wrapped == String {
>>   func bar() -> String {
>> return “Hello"
>>   }
>> }
>> 
>> extension SomeWrapper: Foo where Wrapped == Int {
>>   func bar() -> Int {
>> return 0
>>   }
>> }
> This is a case where we *could* determine that the two conformances will 
> never overlap, because we can statically determine that trying to satisfy the 
> requirements of both extensions at the same time results in a 
> conflict—Wrapped cannot be both equal to an Int and a String. However, I 
> think it’s a bad idea to allow these two conformances, for a couple of 
> reasons:
> 
> (1) It’s going to immediately feature-creep as developers want to be able to 
> treat more kinds of extensions as non-overlapping, e.g., calling two 
> protocols mutually-exclusive (Russ’s example), or introducing some kind of 
> negative constraint (‘Wrapper: !Foo’) to arbitrarily break overlaps. 

Sure, we probably would see requests like this.  The fundamental issue here IMO 
is that type systems are great until they don’t let you express something that 
is relatively obvious conceptually, such as the above example.  This if ok as 
long as there is an alternative available that isn’t clearly worse (as in more 
boilerplate-y, less expressive, etc) and it is easily assimilated by the 
community using the language.  But it becomes very frustrating when that isn’t 
the case.  I’m not sure how often we will fall into the latter bucket because 
of this restriction but it seems likely to happen from time to time.

> (2) The issues I mentioned to Russ about the type checker having to treat 
> these as disjunctions, which can lead us into yet more exponential behavior.

Does Dave’s idea of not treating SomeWrapper itself as a type help at all here? 
 That is how I also conceptualize things.  SomeWrapper is a “type constructor” 
and SomeWrapper is a type.

> (3) I don’t think it’s good design; if you’re going to write an extension to 
> make type X conform to protocol P, you should do so in the most general way 
> that is reasonable for X and P—not pick the one-off case you need this 
> moment. This way, when you do hit two ways in which X conforms to P, the 
> compile complains and nudges you to factor the conformance into something 
> more reusable and non-overlapping.

I agree with this in principle.  However, sometimes a more performant 
implementation might be possible with more type information (as discussed 
below).  It may also be the case that sometimes the general implementation is 
more difficult to write than is worth it for the current application.

> 
> 
>> Secondarily, I understand the reason for letting the “least specific” 
>> candidate conformance win (it is the most general).  But I wonder if this 
>> might leave performance on the table in some cases where a more specific 
>> implementation could use knowledge of the more specific details to implement 
>> the members more efficiently.  Using the example in your proposal, what if 
>> knowing `T` conforms to `S`, not just `R` allows `X5` to provide a more 
>> efficient implementation of the members of `P` and `R`?  If so, it seems 
>> unfortunate to leave that performance on the table.  Is this a valid 
>> concern?  Or is it unlikely to come up often enough in practice to matter?
> 
> 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 

Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-30 Thread plx via swift-evolution

> On Sep 28, 2016, at 5:53 PM, Douglas Gregor  wrote:
> 
> 
>> On Sep 28, 2016, at 1:28 PM, plx via swift-evolution 
>> > wrote:
>> 
>> It’s good to see this starting to happen!
>> 
>> Is the decision on "no-overlapping-conformances” something that’s seen-as 
>> set in stone permanently, set in stone for the near future, or perhaps at 
>> least somewhat open to reconsideration at the present moment?
> 
> There hasn’t been a decision per se, so it that sense it’s open to 
> reconsideration.

I see. A related question: if overlapping conditional conformances are 
disallowed in Swift 4, would e.g. ABI concerns make it infeasible to relax that 
restriction in future Swift (5, 6, X, etc.)? 

FWIW my overall 2c is that the right move right now is to leave out overlapping 
conformances due to the complexity…as long as doing so now doesn’t 
realistically mean never being able to relax that restriction at some later 
date. I realize it’s always *possible* to relax it, so to try and be even 
clearer I really mean “possible to relax it without having to compromise on 
things like ABI-stability (etc.)”.

Also FWIW my suspicion is that in the absence of overlapping conformances some 
real pain points will be discovered—and those points *could* be addressed via 
overlapping conformances—but I also suspect that the majority of these pain 
points will also be addressable via some simpler mechanism (a constrained form 
of overlapping, macros, easy wrapper synthesis, etc.).

Thus I’m in favor of banning conditional conformances for now unless doing so 
now would be the same as doing so “forever”, so to speak.

> I have a strong *personal* bias against overlapping conformances, because I 
> feel that the amount of complexity that they introduce into the language and 
> its implementation far outweigh any benefits. Additionally, they enable use 
> cases (e.g., static metaprogramming-ish tricks) that I feel would be actively 
> harmful to the Swift language’s understandability. Generics systems can get 
> very complicated very quickly, so any extension needs to be strongly 
> motivated by use cases to matter to all or most Swift developers.

This is purely anecdotal but I had a lot of utility code laying around that I’d 
marked with notes like `// TODO: revisit once conditional conformances are 
available`.

When I was leaving those notes I was expecting to need overlapping conformances 
often, but I reviewed them *before* replying and I actually haven’t found an 
example where having overlapping conformances is both (1) a significant win and 
also (2) a win in a way that’d be of broad, general interest.

- 80% have no real need for overlapping conditional conformances
- 15% might have “elegance gains” but nothing practically-significant
- 5% would *probably* see real gains but are likely not of broad interest

…which wasn’t what I was expecting, but leaves me a lot more comfortable 
without overlapping conformances for now than I was in the abstract.

> 
>   - Doug
> 
>> 
>>> On Sep 26, 2016, at 7:18 PM, Douglas Gregor via swift-evolution 
>>> > wrote:
>>> 
>>> Conditional conformances
>>> 
>>> Proposal: SE- 
>>> 
>>> Author: Doug Gregor 
>>> Review Manager: TBD
>>> Status: Awaiting review
>>> During the review process, add the following fields as needed:
>>> 
>>> Decision Notes: Rationale 
>>> , Additional Commentary 
>>> 
>>> Bugs: SR- , SR- 
>>> 
>>> Previous Revision: 1 
>>> 
>>> Previous Proposal: SE- 
>>> 
>>>  
>>> Introduction
>>> 
>>> Conditional conformances express the notion that a generic type will 
>>> conform to a particular protocol only when it's type arguments meet certain 
>>> requirements. For example, the Array collection can implement the Equatable 
>>> protocol only when its elements are themselves Equatable, which can be 
>>> expressed via the following conditional conformance on Equatable:
>>> 
>>> extension Array: Equatable where Element: Equatable {
>>>   static func ==(lhs: Array, rhs: Array) -> Bool { ... }
>>> }
>>> This feature is part of the generics manifesto 
>>> 
>>>  because it's something that fits naturally into the generics 

Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-30 Thread Douglas Gregor via swift-evolution

> On Sep 28, 2016, at 4:30 PM, Matthew Johnson  wrote:
> 
>>> Is the decision on "no-overlapping-conformances” something that’s seen-as 
>>> set in stone permanently, set in stone for the near future, or perhaps at 
>>> least somewhat open to reconsideration at the present moment?
>> 
>> There hasn’t been a decision per se, so it that sense it’s open to 
>> reconsideration.
>> 
>> I have a strong *personal* bias against overlapping conformances, because I 
>> feel that the amount of complexity that they introduce into the language and 
>> its implementation far outweigh any benefits.
> 
> I would like a bit further clarification on what the prohibition of 
> overlapping conformances implies.

I think I presented it poorly in the proposal, and will see if I can find a 
clearer exposition (for posterity, if not soon enough to aid the review).

>  For example, consider this modification of your example in a Swift that 
> allows for same type constraints in extensions.  Would this be allowed?

Short answer: no. Longer answer below.

>  There would be two different conformances to Foo for SomeWrapper, but they 
> would never “overlap” (i.e. both be candidates for the same concrete type).
> struct SomeWrapper {
>   let wrapped: Wrapped
> }
> 
> protocol Foo {
> associatedtype Bar
>   func bar() -> Bar
> }
> 
> extension SomeWrapper: Equatable where Wrapped == String {
>   func bar() -> String {
> return “Hello"
>   }
> }
> 
> extension SomeWrapper: Equatable where Wrapped == Int {
>   func bar() -> Int {
> return 0
>   }
> }
This is a case where we *could* determine that the two conformances will never 
overlap, because we can statically determine that trying to satisfy the 
requirements of both extensions at the same time results in a conflict—Wrapped 
cannot be both equal to an Int and a String. However, I think it’s a bad idea 
to allow these two conformances, for a couple of reasons:

(1) It’s going to immediately feature-creep as developers want to be able to 
treat more kinds of extensions as non-overlapping, e.g., calling two protocols 
mutually-exclusive (Russ’s example), or introducing some kind of negative 
constraint (‘Wrapper: !Foo’) to arbitrarily break overlaps. 
(2) The issues I mentioned to Russ about the type checker having to treat these 
as disjunctions, which can lead us into yet more exponential behavior.
(3) I don’t think it’s good design; if you’re going to write an extension to 
make type X conform to protocol P, you should do so in the most general way 
that is reasonable for X and P—not pick the one-off case you need this moment. 
This way, when you do hit two ways in which X conforms to P, the compile 
complains and nudges you to factor the conformance into something more reusable 
and non-overlapping.


> Secondarily, I understand the reason for letting the “least specific” 
> candidate conformance win (it is the most general).  But I wonder if this 
> might leave performance on the table in some cases where a more specific 
> implementation could use knowledge of the more specific details to implement 
> the members more efficiently.  Using the example in your proposal, what if 
> knowing `T` conforms to `S`, not just `R` allows `X5` to provide a more 
> efficient implementation of the members of `P` and `R`?  If so, it seems 
> unfortunate to leave that performance on the table.  Is this a valid concern? 
>  Or is it unlikely to come up often enough in practice to matter?

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 { 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(_ value: u) {
  value.f()
}

generic(X())

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.

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.

- Doug


___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-29 Thread Douglas Gregor via swift-evolution

> On Sep 29, 2016, at 3:05 PM, Russ Bishop  wrote:
> 
> 
>> On Sep 29, 2016, at 11:12 AM, Douglas Gregor > > wrote:
>> 
>>> 
>>> On Sep 28, 2016, at 9:48 PM, Russ Bishop >> > wrote:
>>> 
>>> What other designs were considered and rejected? It seems like some kind of 
>>> escape hatch would be preferred if you happen to get into this situation, 
>>> though you make some really good points about the pitfalls.
>> 
>> I don’t have a fully-baked alternative proposal—it would probably have to 
>> involve some kind of preference rule for picking the “best” set of 
>> (consistent!) conformances to satisfy a particular request, introduce a 
>> disambiguation syntax for cases where that preference rule does the wrong 
>> thing, and some way of teaching the dynamic-casting machinery to do the same 
>> thing.
> 
> Yeah your description is already sounding like a lot of work :)
> 
> 
>> 
>>> Just to clarify when you say “bans” do you mean if Wrapped: Equatable & 
>>> HasIdentity then SomeWrapper is not Equatable, or do you mean you get a 
>>> compile error because there are two constrained conformances SomeWrapper: 
>>> Equatable? 
>> 
>> You get a compile error if there are two conformances of SomeWrapper to 
>> Equatable; it doesn’t actually matter whether they are conditional, but 
>> people are far more likely to expect to be able to having overlapping 
>> conditional conformances.
> 
> Just to clarify in my mind, the problem here is that Swift would need runtime 
> machinery to look at Wrapped and select the conformance to Equatable based on 
> whether Wrapped: Equatable or Wrapped: HasIdentity. Is that right?


Correct. And diagnose / disambiguate if there are multiple conformances that 
match.

> Otherwise with the proposal as written Swift would need to check Wrapped to 
> validate the constraints but once it does there is only one implementation of 
> the conformance to pick from. 

Right.

> I believe you about the type checker, I’m just naively assuming inserting a 
> table to select the correct conformance isn’t a big cost because you would 
> canonicalize the constraints and being disjoint for any type T there would 
> only ever be one matching entry.

The table computation would have to be a runtime thing, because we don’t know 
all of the conformances until then, but yes—it’s doable.

>> 
>>> What would be the problem with allowing multiple conformances to Equatable 
>>> so long as the constraints are disjoint 
>> 
>> From the language perspective, “disjoint” would have to mean that there are 
>> requirements that actively conflict, e.g., one extension has 
>> “Wrapped.Element == Int” and the other has “Wrapped.Element == String”.
> 
> Yes, I was also imagining protocols so long as there is no protocol they 
> share in common except the empty protocol.

The compiler won’t know that a given type can’t conform to two specific 
protocols, though, unless they have some kind of direct conflict (like my 
example above of Wrapped.Element being equated to two different concrete types) 
or we have some mechanism in the language to state that two protocols are 
mutually exclusive.

>>> or the concrete type only adopts one of the available protocols?
>> 
>> Unless you assume that you have a fully-determined, closed system where you 
>> know about every potential conformance of a concrete type, this isn’t a 
>> question that can be answered at compile time.
> 
> The problem is importing a random library can immediately introduce breakage 
> when it is a compile error, or worse if both reference a shared library you 
> also import… unless we’re saying extensions of types outside your module are 
> only visible in the declaring module which is pretty restrictive e.g. some UI 
> toolkit extending UIKit/AppKit classes with conveniences, or extending Array 
> to say it CanLayout if elements are views where calling a.layout() tells all 
> the views in the array to layout. In that example neither the views nor Array 
> would be declared in the module doing the extending.
> 
> Now let’s say I want to use the swift-protobuf library and I also use 
> GenericSocialMediaService’ SDK that also incorporates swift-protobuf. I’m 
> just imagining what happens when we both try to define extensions. It would 
> be nice if they could declare Array: ProtobufMessage where Element: 
> GSMSEntityProtocol but I was able to provide Array: ProtobufMessage where 
> Element: MyOwnProtocol. 

Yes, I know.

> That said the restrictions can always be relaxed later. I’d rather have this 
> feature without overlapping conformances than not have it.

Right. If we find a model for it that works.

> 
> 
>> 
 With conditional conformances, the question of which extension "wins" the 
 implied conformance begins to matter, because the extensions might have 
 different constraints on them. For example:
 
 struct X4 { }
 

Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-29 Thread Douglas Gregor via swift-evolution


Sent from my iPhone

> On Sep 29, 2016, at 7:45 PM, Jonathan Hull  wrote:
> 
> +1 to conditional conformances in general.
>> >> What other designs were considered and rejected? It seems like some kind 
>> >> of escape hatch would be preferred if you happen to get into this 
>> >> situation, though you make some really good points about the pitfalls.
>> > 
>> > I don’t have a fully-baked alternative proposal—it would probably have to 
>> > involve some kind of preference rule for picking the “best” set of 
>> > (consistent!) conformances to satisfy a particular request, introduce a 
>> > disambiguation syntax for cases where that preference rule does the wrong 
>> > thing, and some way of teaching the dynamic-casting machinery to do the 
>> > same thing.
>> 
>> Yeah your description is already sounding like a lot of work :)
> I still think it is worth looking at this issue in general though. I think it 
> is one of the big holes in swift’s grammar, and the sooner we find a way to 
> express distributed ordering, the less churn it will cause when we make the 
> change (and the more consistency we can have across language features which 
> share this issue).  It doesn’t necessarily have to be fixed in this proposal 
> though, as long as we don’t paint ourselves into a corner.

I agree that we need to address the inability to disambiguate in the language. 
I'd like to see it addressed comprehensively, so we don't end up with one 
syntax in part of the language that doesn't work in another, similar part of 
the language. So it should cover "I want to call this specific thing in this 
protocol extension defined in this other module..." and "I want to this method 
to implement that requirement of this specific protocol" and such. 

In a sense, this particular proposal doesn't "need" disambiguation because it 
bans ambiguities. 

> 
>> You get a compile error if there are two conformances of SomeWrapper to 
>> Equatable; it doesn’t actually matter whether they are conditional, but 
>> people are far more likely to expect to be able to having overlapping 
>> conditional conformances.
>> 
>> Slightly off-topic but I was hit quick badly by this recently because two 
>> libraries I was trying to import both conformed UIControlState to Hashable 
>> to be able to use it as Dictionary indices. It seems like something that 
>> might happen kind of regularly with important protocols like Hashable and 
>> Equatable.
> 
> I agree with David that the non-overlapping issue is going to come up a lot 
> around things like Equatable.

Yeah, it's likely to happen most with libraries imported from C/Objective-C and 
the standard library's protocols, because the C/Objective-C types won't have 
considered those conformances initially and yet everyone uses the standard 
library protocols. 

> 
> One potential solution would be to have the ability to mark a conditionally 
> conforming extension as “weak” (or another term which has been bikeshedded).  
> In this case, it would then act similarly to default implementations of 
> protocols.  That is, it would provide conformance if no one else was, but 
> defer to any other implementation which is available. This means library 
> authors can provide basic conditional conformance without locking out more 
> specific implementations.  This deferral would likely be on a method by 
> method basis (similar to default protocol implementations), though the “weak” 
> (or equivalent) annotation would apply to the extension as a whole.

This is roughly the shape of solutions we've discussed. There is some runtime 
validation we might need---for example, to make sure all of the conformances 
define the same associated type witnesses---but it's something we can probably 
do via lazy deduplication at runtime. 

  - Doug

> 
> Thanks,
> Jon
> 
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-29 Thread Jonathan Hull via swift-evolution
+1 to conditional conformances in general.
> >> What other designs were considered and rejected? It seems like some kind 
> >> of escape hatch would be preferred if you happen to get into this 
> >> situation, though you make some really good points about the pitfalls.
> > 
> > I don’t have a fully-baked alternative proposal—it would probably have to 
> > involve some kind of preference rule for picking the “best” set of 
> > (consistent!) conformances to satisfy a particular request, introduce a 
> > disambiguation syntax for cases where that preference rule does the wrong 
> > thing, and some way of teaching the dynamic-casting machinery to do the 
> > same thing.
> 
> Yeah your description is already sounding like a lot of work :)
I still think it is worth looking at this issue in general though. I think it 
is one of the big holes in swift’s grammar, and the sooner we find a way to 
express distributed ordering, the less churn it will cause when we make the 
change (and the more consistency we can have across language features which 
share this issue).  It doesn’t necessarily have to be fixed in this proposal 
though, as long as we don’t paint ourselves into a corner.

> You get a compile error if there are two conformances of SomeWrapper to 
> Equatable; it doesn’t actually matter whether they are conditional, but 
> people are far more likely to expect to be able to having overlapping 
> conditional conformances.
> 
> Slightly off-topic but I was hit quick badly by this recently because two 
> libraries I was trying to import both conformed UIControlState to Hashable to 
> be able to use it as Dictionary indices. It seems like something that might 
> happen kind of regularly with important protocols like Hashable and Equatable.

I agree with David that the non-overlapping issue is going to come up a lot 
around things like Equatable.

One potential solution would be to have the ability to mark a conditionally 
conforming extension as “weak” (or another term which has been bikeshedded).  
In this case, it would then act similarly to default implementations of 
protocols.  That is, it would provide conformance if no one else was, but defer 
to any other implementation which is available. This means library authors can 
provide basic conditional conformance without locking out more specific 
implementations.  This deferral would likely be on a method by method basis 
(similar to default protocol implementations), though the “weak” (or 
equivalent) annotation would apply to the extension as a whole.

Thanks,
Jon

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-29 Thread Russ Bishop via swift-evolution

> On Sep 29, 2016, at 11:12 AM, Douglas Gregor  wrote:
> 
>> 
>> On Sep 28, 2016, at 9:48 PM, Russ Bishop > > wrote:
>> 
>> What other designs were considered and rejected? It seems like some kind of 
>> escape hatch would be preferred if you happen to get into this situation, 
>> though you make some really good points about the pitfalls.
> 
> I don’t have a fully-baked alternative proposal—it would probably have to 
> involve some kind of preference rule for picking the “best” set of 
> (consistent!) conformances to satisfy a particular request, introduce a 
> disambiguation syntax for cases where that preference rule does the wrong 
> thing, and some way of teaching the dynamic-casting machinery to do the same 
> thing.

Yeah your description is already sounding like a lot of work :)


> 
>> Just to clarify when you say “bans” do you mean if Wrapped: Equatable & 
>> HasIdentity then SomeWrapper is not Equatable, or do you mean you get a 
>> compile error because there are two constrained conformances SomeWrapper: 
>> Equatable? 
> 
> You get a compile error if there are two conformances of SomeWrapper to 
> Equatable; it doesn’t actually matter whether they are conditional, but 
> people are far more likely to expect to be able to having overlapping 
> conditional conformances.

Just to clarify in my mind, the problem here is that Swift would need runtime 
machinery to look at Wrapped and select the conformance to Equatable based on 
whether Wrapped: Equatable or Wrapped: HasIdentity. Is that right? Otherwise 
with the proposal as written Swift would need to check Wrapped to validate the 
constraints but once it does there is only one implementation of the 
conformance to pick from. 

I believe you about the type checker, I’m just naively assuming inserting a 
table to select the correct conformance isn’t a big cost because you would 
canonicalize the constraints and being disjoint for any type T there would only 
ever be one matching entry.




> 
>> What would be the problem with allowing multiple conformances to Equatable 
>> so long as the constraints are disjoint 
> 
> From the language perspective, “disjoint” would have to mean that there are 
> requirements that actively conflict, e.g., one extension has “Wrapped.Element 
> == Int” and the other has “Wrapped.Element == String”.

Yes, I was also imagining protocols so long as there is no protocol they share 
in common except the empty protocol.


> 
> There are implementation issues here deep in the type checker, e.g., because 
> if a given type T can potential conform to a protocol P in multiple ways, it 
> introduces a disjunction in the constraint solver that can push the 
> constraint solver to be Even More Exponential.

That’s Bad ™️



> For me, there’s also the usability issue, and that’s the key argument: the 
> *human* has to reason about these things, too, and it is a whole lot simpler 
> if “does T conform to P?” can only be answered in one way. I don’t think the 
> use cases for having overlapping conformances justify such a drastic increase 
> in complexity across the feature.

Constraints are already introducing some complexity there (which is worth it 
IMHO). You can’t just answer the question is Array: Equatable? You need to know 
about T. 


> 
>> or the concrete type only adopts one of the available protocols?
> 
> Unless you assume that you have a fully-determined, closed system where you 
> know about every potential conformance of a concrete type, this isn’t a 
> question that can be answered at compile time.

The problem is importing a random library can immediately introduce breakage 
when it is a compile error, or worse if both reference a shared library you 
also import… unless we’re saying extensions of types outside your module are 
only visible in the declaring module which is pretty restrictive e.g. some UI 
toolkit extending UIKit/AppKit classes with conveniences, or extending Array to 
say it CanLayout if elements are views where calling a.layout() tells all the 
views in the array to layout. In that example neither the views nor Array would 
be declared in the module doing the extending.

Now let’s say I want to use the swift-protobuf library and I also use 
GenericSocialMediaService’ SDK that also incorporates swift-protobuf. I’m just 
imagining what happens when we both try to define extensions. It would be nice 
if they could declare Array: ProtobufMessage where Element: GSMSEntityProtocol 
but I was able to provide Array: ProtobufMessage where Element: MyOwnProtocol. 


That said the restrictions can always be relaxed later. I’d rather have this 
feature without overlapping conformances than not have it.



> 
>>> With conditional conformances, the question of which extension "wins" the 
>>> implied conformance begins to matter, because the extensions might have 
>>> different constraints on them. For example:
>>> 
>>> struct X4 { }
>>> 
>>> 

Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-29 Thread David Hart via swift-evolution

> On 29 Sep 2016, at 20:12, Douglas Gregor via swift-evolution 
>  wrote:
> 
> You get a compile error if there are two conformances of SomeWrapper to 
> Equatable; it doesn’t actually matter whether they are conditional, but 
> people are far more likely to expect to be able to having overlapping 
> conditional conformances.

Slightly off-topic but I was hit quick badly by this recently because two 
libraries I was trying to import both conformed UIControlState to Hashable to 
be able to use it as Dictionary indices. It seems like something that might 
happen kind of regularly with important protocols like Hashable and Equatable.

Is there any plans to address those issues and might it have an effect on this 
proposal?___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-29 Thread Douglas Gregor via swift-evolution

> On Sep 28, 2016, at 9:48 PM, Russ Bishop  wrote:
> 
> 
>> On Sep 26, 2016, at 5:18 PM, Douglas Gregor via swift-evolution 
>> > wrote:
>> 
>> Conditional conformances
>> 
>>  
>> Disallow
>>  overlapping conformances
>> 
>> With conditional conformances, it is possible to express that a given 
>> generic type can conform to the same protocol in two different ways, 
>> depending on the capabilities of its type arguments. For example:
>> 
>> …
>> 
>> Note that, for an arbitrary type T, there are four potential answers to the 
>> question of whether SomeWrapper conforms to Equatable:
>> 
>> No, it does not conform because T is neither Equatable nor HasIdentity.
>> Yes, it conforms via the first extension of SomeWrapper because T conforms 
>> to Equatable.
>> Yes, it conforms via the second extension of SomeWrapper because T conforms 
>> to HasIdentity.
>> Ambiguity, because T conforms to both Equatable and HasIdentity.
>> It is due to the possibility of #4 occurring that we refer to the two 
>> conditional conformances in the example as overlapping. There are designs 
>> that would allow one to address the ambiguity
>> 
>> …
>> 
>> For these reasons, this proposal bans overlapping conformances entirely. 
> 
> What other designs were considered and rejected? It seems like some kind of 
> escape hatch would be preferred if you happen to get into this situation, 
> though you make some really good points about the pitfalls.

I don’t have a fully-baked alternative proposal—it would probably have to 
involve some kind of preference rule for picking the “best” set of 
(consistent!) conformances to satisfy a particular request, introduce a 
disambiguation syntax for cases where that preference rule does the wrong 
thing, and some way of teaching the dynamic-casting machinery to do the same 
thing.

> Just to clarify when you say “bans” do you mean if Wrapped: Equatable & 
> HasIdentity then SomeWrapper is not Equatable, or do you mean you get a 
> compile error because there are two constrained conformances SomeWrapper: 
> Equatable?

You get a compile error if there are two conformances of SomeWrapper to 
Equatable; it doesn’t actually matter whether they are conditional, but people 
are far more likely to expect to be able to having overlapping conditional 
conformances.

> What would be the problem with allowing multiple conformances to Equatable so 
> long as the constraints are disjoint

>From the language perspective, “disjoint” would have to mean that there are 
>requirements that actively conflict, e.g., one extension has “Wrapped.Element 
>== Int” and the other has “Wrapped.Element == String”.

There are implementation issues here deep in the type checker, e.g., because if 
a given type T can potential conform to a protocol P in multiple ways, it 
introduces a disjunction in the constraint solver that can push the constraint 
solver to be Even More Exponential.

For me, there’s also the usability issue, and that’s the key argument: the 
*human* has to reason about these things, too, and it is a whole lot simpler if 
“does T conform to P?” can only be answered in one way. I don’t think the use 
cases for having overlapping conformances justify such a drastic increase in 
complexity across the feature.

> or the concrete type only adopts one of the available protocols?

Unless you assume that you have a fully-determined, closed system where you 
know about every potential conformance of a concrete type, this isn’t a 
question that can be answered at compile time.

> 
>>  
>> Implied
>>  conditional conformances
>> 
>> Stating conformance to a protocol implicitly states conformances to any of 
>> the protocols that it inherits. This is the case in Swift today, although 
>> most developers likely don't realize the rules it follows. For example:
>> 
>> protocol P { }
>> protocol Q : P { }
>> protocol R : P { }
>> 
>> struct X1 { }
>> struct X2 { }
>> struct X3 { }
>> 
>> extension X1: Q { }  // implies conformance to P
>> 
>> extension X2: Q { }  // would imply conformance to P, but...
>> extension X2: P { }  // explicitly-stated conformance to P "wins"
>> 
>> extension X3: Q { }  // implies conformance to P
>> extension X3: R { }  // also implies conformance to P
>>  // one will "win"; which is unspecified
> On X2 you’re declaring a redundant conformance to P but any protocol 
> extensions will prefer Q and the compiler won’t let you redefine any members 
> so you’ll have an incomplete conformance. Any explicit conformances (on the 
> type or in extensions) are preferred over the defaults from the protocol 
> extension, but that’s not new. I must be missing something, how would this be 
> 

Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-28 Thread Russ Bishop via swift-evolution

> On Sep 26, 2016, at 5:18 PM, Douglas Gregor via swift-evolution 
>  wrote:
> 
> Conditional conformances
> 
>  
> Disallow
>  overlapping conformances
> 
> With conditional conformances, it is possible to express that a given generic 
> type can conform to the same protocol in two different ways, depending on the 
> capabilities of its type arguments. For example:
> 
> …
> 
> Note that, for an arbitrary type T, there are four potential answers to the 
> question of whether SomeWrapper conforms to Equatable:
> 
> No, it does not conform because T is neither Equatable nor HasIdentity.
> Yes, it conforms via the first extension of SomeWrapper because T conforms to 
> Equatable.
> Yes, it conforms via the second extension of SomeWrapper because T conforms 
> to HasIdentity.
> Ambiguity, because T conforms to both Equatable and HasIdentity.
> It is due to the possibility of #4 occurring that we refer to the two 
> conditional conformances in the example as overlapping. There are designs 
> that would allow one to address the ambiguity
> 
> …
> 
> For these reasons, this proposal bans overlapping conformances entirely. 

What other designs were considered and rejected? It seems like some kind of 
escape hatch would be preferred if you happen to get into this situation, 
though you make some really good points about the pitfalls.

Just to clarify when you say “bans” do you mean if Wrapped: Equatable & 
HasIdentity then SomeWrapper is not Equatable, or do you mean you get a compile 
error because there are two constrained conformances SomeWrapper: Equatable? 
What would be the problem with allowing multiple conformances to Equatable so 
long as the constraints are disjoint or the concrete type only adopts one of 
the available protocols?

>  
> Implied
>  conditional conformances
> 
> Stating conformance to a protocol implicitly states conformances to any of 
> the protocols that it inherits. This is the case in Swift today, although 
> most developers likely don't realize the rules it follows. For example:
> 
> protocol P { }
> protocol Q : P { }
> protocol R : P { }
> 
> struct X1 { }
> struct X2 { }
> struct X3 { }
> 
> extension X1: Q { }  // implies conformance to P
> 
> extension X2: Q { }  // would imply conformance to P, but...
> extension X2: P { }  // explicitly-stated conformance to P "wins"
> 
> extension X3: Q { }  // implies conformance to P
> extension X3: R { }  // also implies conformance to P
>  // one will "win"; which is unspecified
On X2 you’re declaring a redundant conformance to P but any protocol extensions 
will prefer Q and the compiler won’t let you redefine any members so you’ll 
have an incomplete conformance. Any explicit conformances (on the type or in 
extensions) are preferred over the defaults from the protocol extension, but 
that’s not new. I must be missing something, how would this be visible in Swift 
3?

On X3, multiple implementations in protocol extensions are errors today and the 
resolution is to provide an explicit implementation on X3.




> With conditional conformances, the question of which extension "wins" the 
> implied conformance begins to matter, because the extensions might have 
> different constraints on them. For example:
> 
> struct X4 { }
> 
> extension X4: Q where T: Q { }  // implies conformance to P
> extension X4: R where T: R { }  // error: implies overlapping conformance to P
> Both of these constrained extensions imply a conformance to P, but the actual 
> P implied conformances to P are overlapping and, therefore, result in an 
> error.
> 
If the related P conformance were inherited from conformance to Q or R then the 
rules would (IMHO) make more sense. Wouldn’t the extra rule you need simply be 
that either Q or R must provide a complete conformance to P (no mix-n-match)? 

If T implements Q & P why not just ignore T: P which means the X4: R extension 
is no longer relevant. 

It seems like the tricky case is T: P and the same question applies - why not 
just ignore the extensions (X4 in that scenario doesn’t implement Q, R, or 
P). 


Not allowing ambiguity seems like it solves the “which one” problem and 
requiring an extension to provide the entire implementation (no mix-n-match) 
cuts down on the cleverness problem.




> However, in cases where there is a reasonable ordering between the two 
> constrained extensions (i.e., one is more specialized than the other), the 
> less specialized constrained extension should "win" the implied conformance. 
> Continuing the example from above:
> 
> protocol S: R { }
> 
> struct X5 { }
> 
> extension X5: R where T: R { }  // "wins" implied conformance to P, because
> extension X5: S where T: S { }  // the extension where "T: S" is more 

Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-28 Thread Douglas Gregor via swift-evolution

> On Sep 28, 2016, at 1:28 PM, plx via swift-evolution 
>  wrote:
> 
> It’s good to see this starting to happen!
> 
> Is the decision on "no-overlapping-conformances” something that’s seen-as set 
> in stone permanently, set in stone for the near future, or perhaps at least 
> somewhat open to reconsideration at the present moment?

There hasn’t been a decision per se, so it that sense it’s open to 
reconsideration.

I have a strong *personal* bias against overlapping conformances, because I 
feel that the amount of complexity that they introduce into the language and 
its implementation far outweigh any benefits. Additionally, they enable use 
cases (e.g., static metaprogramming-ish tricks) that I feel would be actively 
harmful to the Swift language’s understandability. Generics systems can get 
very complicated very quickly, so any extension needs to be strongly motivated 
by use cases to matter to all or most Swift developers.

- Doug

> 
>> On Sep 26, 2016, at 7:18 PM, Douglas Gregor via swift-evolution 
>> > wrote:
>> 
>> Conditional conformances
>> 
>> Proposal: SE- 
>> 
>> Author: Doug Gregor 
>> Review Manager: TBD
>> Status: Awaiting review
>> During the review process, add the following fields as needed:
>> 
>> Decision Notes: Rationale 
>> , Additional Commentary 
>> 
>> Bugs: SR- , SR- 
>> 
>> Previous Revision: 1 
>> 
>> Previous Proposal: SE- 
>> 
>>  
>> Introduction
>> 
>> Conditional conformances express the notion that a generic type will conform 
>> to a particular protocol only when it's type arguments meet certain 
>> requirements. For example, the Array collection can implement the Equatable 
>> protocol only when its elements are themselves Equatable, which can be 
>> expressed via the following conditional conformance on Equatable:
>> 
>> extension Array: Equatable where Element: Equatable {
>>   static func ==(lhs: Array, rhs: Array) -> Bool { ... }
>> }
>> This feature is part of the generics manifesto 
>> 
>>  because it's something that fits naturally into the generics model and is 
>> expected to have a high impact on the Swift standard library.
>> 
>> Swift-evolution thread: TBD: Discussion thread topic for that proposal 
>> 
>>  
>> Motivation
>> 
>> Conditional conformances address a hole in the composability of the generics 
>> system. Continuing the Array example from above, it's always been the case 
>> that one could use the == operator on two arrays of Equatable type, e.g., 
>> [Int]() == [Int]() would succeed. However, it doesn't compose: arrays of 
>> arrays of Equatable types cannot be compared (e.g.,[Int] 
>> ==
>>  [Int] 
>> will
>>  fail to compile) because, even though there is an==for arrays of 
>> Equatabletype, the arrays themselves are neverEquatable`.
>> 
>> Conditional conformances are particularly powerful when building generic 
>> adapter types, which are intended to reflect the capabilities of their type 
>> arguments. For example, consider the "lazy" functionality of the Swift 
>> standard library's collections: using the lazy member of a sequence produces 
>> a lazy adapter that conforms to the Sequence protocol, while using the lazy 
>> member of a collection produces a lazy adapter that conforms to the 
>> Collection protocol. In Swift 3, the only way to model this is with 
>> different types. For example, the Swift standard library has four similar 
>> generic types to handle a lazy collection: LazySequence, LazyCollection, 
>> LazyBidirectionalCollection, and LazyRandomAccessCollection. The Swift 
>> standard library uses overloading of the lazy property to decide among these:
>> 
>> extension Sequence {
>>   var lazy: LazySequence { ... }
>> }
>> 
>> extension Collection {
>>   var lazy: LazyCollection { ... }
>> }
>> 
>> extension BidirectionalCollection {
>>   var lazy: LazyBidirectionalCollection { ... }
>> }
>> 
>> 

Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-28 Thread plx via swift-evolution
It’s good to see this starting to happen!

Is the decision on "no-overlapping-conformances” something that’s seen-as set 
in stone permanently, set in stone for the near future, or perhaps at least 
somewhat open to reconsideration at the present moment?

> On Sep 26, 2016, at 7:18 PM, Douglas Gregor via swift-evolution 
>  wrote:
> 
> Conditional conformances
> 
> Proposal: SE- 
> 
> Author: Doug Gregor 
> Review Manager: TBD
> Status: Awaiting review
> During the review process, add the following fields as needed:
> 
> Decision Notes: Rationale 
> , Additional Commentary 
> 
> Bugs: SR- , SR- 
> 
> Previous Revision: 1 
> 
> Previous Proposal: SE- 
> 
>  
> Introduction
> 
> Conditional conformances express the notion that a generic type will conform 
> to a particular protocol only when it's type arguments meet certain 
> requirements. For example, the Array collection can implement the Equatable 
> protocol only when its elements are themselves Equatable, which can be 
> expressed via the following conditional conformance on Equatable:
> 
> extension Array: Equatable where Element: Equatable {
>   static func ==(lhs: Array, rhs: Array) -> Bool { ... }
> }
> This feature is part of the generics manifesto 
> 
>  because it's something that fits naturally into the generics model and is 
> expected to have a high impact on the Swift standard library.
> 
> Swift-evolution thread: TBD: Discussion thread topic for that proposal 
> 
>  
> Motivation
> 
> Conditional conformances address a hole in the composability of the generics 
> system. Continuing the Array example from above, it's always been the case 
> that one could use the == operator on two arrays of Equatable type, e.g., 
> [Int]() == [Int]() would succeed. However, it doesn't compose: arrays of 
> arrays of Equatable types cannot be compared (e.g.,[Int] 
> ==
>  [Int] 
> will
>  fail to compile) because, even though there is an==for arrays of 
> Equatabletype, the arrays themselves are neverEquatable`.
> 
> Conditional conformances are particularly powerful when building generic 
> adapter types, which are intended to reflect the capabilities of their type 
> arguments. For example, consider the "lazy" functionality of the Swift 
> standard library's collections: using the lazy member of a sequence produces 
> a lazy adapter that conforms to the Sequence protocol, while using the lazy 
> member of a collection produces a lazy adapter that conforms to the 
> Collection protocol. In Swift 3, the only way to model this is with different 
> types. For example, the Swift standard library has four similar generic types 
> to handle a lazy collection: LazySequence, LazyCollection, 
> LazyBidirectionalCollection, and LazyRandomAccessCollection. The Swift 
> standard library uses overloading of the lazy property to decide among these:
> 
> extension Sequence {
>   var lazy: LazySequence { ... }
> }
> 
> extension Collection {
>   var lazy: LazyCollection { ... }
> }
> 
> extension BidirectionalCollection {
>   var lazy: LazyBidirectionalCollection { ... }
> }
> 
> extension RandomAccessCollection {
>   var lazy: LazyRandomAccessCollection { ... }
> }
> This approach causes an enormous amount of repetition, and doesn't scale well 
> because each more-capable type has to re-implement (or somehow forward the 
> implementation of) all of the APIs of the less-capable versions. With 
> conditional conformances, one can provide a single generic wrapper type whose 
> basic requirements meet the lowest common denominator (e.g., Sequence), but 
> which scale their capabilities with their type argument (e.g., the 
> LazySequence conforms to Collection when the type argument does, and so on).
> 
>  
> Proposed
>  solution
> 
> In a nutshell, the proposed solution is to allow a constrained extension of a 
> struct, enum, or 

Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-28 Thread Jordan Rose via swift-evolution

> On Sep 28, 2016, at 9:51, Douglas Gregor  wrote:
> 
> 
>> On Sep 27, 2016, at 5:06 PM, Jordan Rose > > wrote:
>> 
>> Great job thinking this all through (as usual), and I’ll be very happy to 
>> have Optional and Array become Equatable. Here’s some of my thoughts on the 
>> library evolution aspect of this:
>> 
>> - Removing a conditional conformance isn’t allowed, obviously.
>> - Adding a conditional conformance is just like adding an unconditional 
>> conformance—it needs availability info.
> 
> Right. The main wrinkle I see here is that, when you add a conditional 
> conformance, you will effectively end up with overlapping conformances when 
> running an old application against a new library. Do you want me to capture 
> these cases in the proposal in a section on “Resilience” or “Library 
> Evolution”, like I’ve tried to capture the effect on ABI Stability? (I think 
> that makes sense)

Sure, yes please. (I think the main point is that the "conditional" doesn't 
make a difference here.)


> 
>> - It would be nice™ if making a conditional conformance more general was 
>> allowed. Since the plan doesn't allow overlapping conformances, I think this 
>> is actually implementable: just don’t put the constraints in the symbol 
>> name. I don’t know how to represent the backwards-deploying aspects of this 
>> right now, so it probably makes sense to forbid it today, but I think it 
>> would be nice if the implementation left the door open.
> 
> Yeah. It’s a different set of witness tables that one would need to gather to 
> use the conditional conformance in the newer version of the library vs. in an 
> older version of a library. That’s okay if we leave the 
> witness-table-gathering to the runtime, but not so great if we statically 
> provide the witness tables.

This confuses me. Why aren't we just using the minimal (unconditional) 
conformance representation, and then pulling the associated type witness tables 
out dynamically? Is that significantly more expensive? (Am I just missing 
something?)


> 
> 
>> On that note, what happens here?
>> 
>> // Module Lib
>> public protocol Base {}
>> public protocol Sub: Base {}
>> public protocol Special: Sub {}
>> 
>> public struct Impl {}
>> extension Impl: Special where T: Special {}
>> 
>> 
>> // Module Client
>> import Lib
>> 
>> extension Impl: Sub where T: Sub {}
>> 
>> I think this gets rejected because Impl already has a conformance to Sub—the 
>> extension in Client, despite being less specialized, shows up too late to 
>> actually declare this conformance “better”. Is that correct?
> 
> Correct. Impl has a conformance to ‘Sub’ in Lib; Client cannot declare a new 
> one, because it overlaps.  Had all of this code been in one module, it would 
> be well-formed, because the implied conformance to ’Sub’ in the first 
> extension would lose to the explicit conformance to Sub in the second 
> (less-specialized) extension.

Thanks!

Jordan

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-28 Thread Goffredo Marocchi via swift-evolution


Sent from my iPhone

> On 28 Sep 2016, at 19:45, Douglas Gregor  wrote:
> 
> 
>> On Sep 28, 2016, at 11:40 AM, Goffredo Marocchi  wrote:
>> 
>> 
>> 
>> Sent from my iPhone
>> 
>>> On 28 Sep 2016, at 17:51, Douglas Gregor via swift-evolution 
>>>  wrote:
>>> 
>>> 
 On Sep 27, 2016, at 5:06 PM, Jordan Rose  wrote:
 
 Great job thinking this all through (as usual), and I’ll be very happy to 
 have Optional and Array become Equatable. Here’s some of my thoughts on 
 the library evolution aspect of this:
 
 - Removing a conditional conformance isn’t allowed, obviously.
 - Adding a conditional conformance is just like adding an unconditional 
 conformance—it needs availability info.
>>> 
>>> Right. The main wrinkle I see here is that, when you add a conditional 
>>> conformance, you will effectively end up with overlapping conformances when 
>>> running an old application against a new library. Do you want me to capture 
>>> these cases in the proposal in a section on “Resilience” or “Library 
>>> Evolution”, like I’ve tried to capture the effect on ABI Stability? (I 
>>> think that makes sense)
>>> 
 - It would be nice™ if making a conditional conformance more general was 
 allowed. Since the plan doesn't allow overlapping conformances, I think 
 this is actually implementable: just don’t put the constraints in the 
 symbol name. I don’t know how to represent the backwards-deploying aspects 
 of this right now, so it probably makes sense to forbid it today, but I 
 think it would be nice if the implementation left the door open.
>>> 
>>> Yeah. It’s a different set of witness tables that one would need to gather 
>>> to use the conditional conformance in the newer version of the library vs. 
>>> in an older version of a library. That’s okay if we leave the 
>>> witness-table-gathering to the runtime, but not so great if we statically 
>>> provide the witness tables.
>>> 
>> 
>> Would this be a case in which the win by having this feature and letting the 
>> runtime gather the witness tables offset the losses from doing his 
>> operations at runtime? I would like to think that in cases like this there 
>> is at least the option to opt for more flexibility.
> 
> 
> I’m sure we can find a reasonable solution to this that doesn’t incur a 
> significant runtime penalty, e.g., by teaching the runtime conformance 
> specialization machinery to handle a “redirecting” specialization that maps 
> from the requirements of the older (more specialized) version to the 
> requirements of the newer (less specialized) version.
> 
>   - Doug
> 

Very glad to hear that Doug :).___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-28 Thread Douglas Gregor via swift-evolution

> On Sep 28, 2016, at 11:40 AM, Goffredo Marocchi  wrote:
> 
> 
> 
> Sent from my iPhone
> 
> On 28 Sep 2016, at 17:51, Douglas Gregor via swift-evolution 
> > wrote:
> 
>> 
>>> On Sep 27, 2016, at 5:06 PM, Jordan Rose >> > wrote:
>>> 
>>> Great job thinking this all through (as usual), and I’ll be very happy to 
>>> have Optional and Array become Equatable. Here’s some of my thoughts on the 
>>> library evolution aspect of this:
>>> 
>>> - Removing a conditional conformance isn’t allowed, obviously.
>>> - Adding a conditional conformance is just like adding an unconditional 
>>> conformance—it needs availability info.
>> 
>> Right. The main wrinkle I see here is that, when you add a conditional 
>> conformance, you will effectively end up with overlapping conformances when 
>> running an old application against a new library. Do you want me to capture 
>> these cases in the proposal in a section on “Resilience” or “Library 
>> Evolution”, like I’ve tried to capture the effect on ABI Stability? (I think 
>> that makes sense)
>> 
>>> - It would be nice™ if making a conditional conformance more general was 
>>> allowed. Since the plan doesn't allow overlapping conformances, I think 
>>> this is actually implementable: just don’t put the constraints in the 
>>> symbol name. I don’t know how to represent the backwards-deploying aspects 
>>> of this right now, so it probably makes sense to forbid it today, but I 
>>> think it would be nice if the implementation left the door open.
>> 
>> Yeah. It’s a different set of witness tables that one would need to gather 
>> to use the conditional conformance in the newer version of the library vs. 
>> in an older version of a library. That’s okay if we leave the 
>> witness-table-gathering to the runtime, but not so great if we statically 
>> provide the witness tables.
>> 
> 
> Would this be a case in which the win by having this feature and letting the 
> runtime gather the witness tables offset the losses from doing his operations 
> at runtime? I would like to think that in cases like this there is at least 
> the option to opt for more flexibility.


I’m sure we can find a reasonable solution to this that doesn’t incur a 
significant runtime penalty, e.g., by teaching the runtime conformance 
specialization machinery to handle a “redirecting” specialization that maps 
from the requirements of the older (more specialized) version to the 
requirements of the newer (less specialized) version.

- Doug

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-28 Thread Goffredo Marocchi via swift-evolution


Sent from my iPhone

> On 28 Sep 2016, at 17:51, Douglas Gregor via swift-evolution 
>  wrote:
> 
> 
>> On Sep 27, 2016, at 5:06 PM, Jordan Rose  wrote:
>> 
>> Great job thinking this all through (as usual), and I’ll be very happy to 
>> have Optional and Array become Equatable. Here’s some of my thoughts on the 
>> library evolution aspect of this:
>> 
>> - Removing a conditional conformance isn’t allowed, obviously.
>> - Adding a conditional conformance is just like adding an unconditional 
>> conformance—it needs availability info.
> 
> Right. The main wrinkle I see here is that, when you add a conditional 
> conformance, you will effectively end up with overlapping conformances when 
> running an old application against a new library. Do you want me to capture 
> these cases in the proposal in a section on “Resilience” or “Library 
> Evolution”, like I’ve tried to capture the effect on ABI Stability? (I think 
> that makes sense)
> 
>> - It would be nice™ if making a conditional conformance more general was 
>> allowed. Since the plan doesn't allow overlapping conformances, I think this 
>> is actually implementable: just don’t put the constraints in the symbol 
>> name. I don’t know how to represent the backwards-deploying aspects of this 
>> right now, so it probably makes sense to forbid it today, but I think it 
>> would be nice if the implementation left the door open.
> 
> Yeah. It’s a different set of witness tables that one would need to gather to 
> use the conditional conformance in the newer version of the library vs. in an 
> older version of a library. That’s okay if we leave the 
> witness-table-gathering to the runtime, but not so great if we statically 
> provide the witness tables.
> 

Would this be a case in which the win by having this feature and letting the 
runtime gather the witness tables offset the losses from doing his operations 
at runtime? I would like to think that in cases like this there is at least the 
option to opt for more flexibility.

> 
>> On that note, what happens here?
>> 
>> // Module Lib
>> public protocol Base {}
>> public protocol Sub: Base {}
>> public protocol Special: Sub {}
>> 
>> public struct Impl {}
>> extension Impl: Special where T: Special {}
>> 
>> 
>> // Module Client
>> import Lib
>> 
>> extension Impl: Sub where T: Sub {}
>> 
>> I think this gets rejected because Impl already has a conformance to Sub—the 
>> extension in Client, despite being less specialized, shows up too late to 
>> actually declare this conformance “better”. Is that correct?
> 
> Correct. Impl has a conformance to ‘Sub’ in Lib; Client cannot declare a new 
> one, because it overlaps.  Had all of this code been in one module, it would 
> be well-formed, because the implied conformance to ’Sub’ in the first 
> extension would lose to the explicit conformance to Sub in the second 
> (less-specialized) extension.
> 
>   - Doug
> 
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-28 Thread Douglas Gregor via swift-evolution

> On Sep 28, 2016, at 2:55 AM, Anton Zhilin  wrote:
> 
> I find the limitation of non-intersection of conditional conformance 
> reqirements quite limiting. Can it be lifted in case there are no overloaded 
> functions between extensions?
> 
> protocol A { func foo() }
> protocol B { func bar() }
> 
> extension Array: A where Element: A {
> func foo() { return self.first!.foo() }
> }
> extension Array: B where Element: B {
> func bar() { return self.first!.bar() }
> }
> 
> let arr: Array
> arr.foo()
> 
> What is ambiguous here?

Nothing. These conformances are not overlapping, because A and B are 
independent protocols. The first extension declares a conditional conformance 
to A, the second declares a conditional conformance to B.

- Doug

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-28 Thread Anton Zhilin via swift-evolution
I find the limitation of non-intersection of conditional conformance
reqirements quite limiting. Can it be lifted in case there are no
overloaded functions between extensions?

protocol A { func foo() }
protocol B { func bar() }

extension Array: A where Element: A {
func foo() { return self.first!.foo() }
}
extension Array: B where Element: B {
func bar() { return self.first!.bar() }
}

let arr: Array
arr.foo()

What is ambiguous here? When we see arr.foo(), we know it's from Array: A
extension, regardless of T, and we just have to check the requirement of
that extension.
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-27 Thread Jordan Rose via swift-evolution
Great job thinking this all through (as usual), and I’ll be very happy to have 
Optional and Array become Equatable. Here’s some of my thoughts on the library 
evolution aspect of this:

- Removing a conditional conformance isn’t allowed, obviously.
- Adding a conditional conformance is just like adding an unconditional 
conformance—it needs availability info.
- It would be nice™ if making a conditional conformance more general was 
allowed. Since the plan doesn't allow overlapping conformances, I think this is 
actually implementable: just don’t put the constraints in the symbol name. I 
don’t know how to represent the backwards-deploying aspects of this right now, 
so it probably makes sense to forbid it today, but I think it would be nice if 
the implementation left the door open.

On that note, what happens here?

// Module Lib
public protocol Base {}
public protocol Sub: Base {}
public protocol Special: Sub {}

public struct Impl {}
extension Impl: Special where T: Special {}


// Module Client
import Lib

extension Impl: Sub where T: Sub {}

I think this gets rejected because Impl already has a conformance to Sub—the 
extension in Client, despite being less specialized, shows up too late to 
actually declare this conformance “better”. Is that correct?

Jordan
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal draft] Conditional conformances

2016-09-26 Thread Robert Widmann via swift-evolution
+1.  I have one purely bureaucratic concern that I couldn't quite find answers 
to on a read through:

Orphan instances and more generally cross-module uniqueness of instances are 
not mentioned.  What's the policy here?  Are we locally unique with respect to 
imported modules or globally unique with respect to all importable modules?

~Robert Widmann

2016/09/26 20:18、Douglas Gregor via swift-evolution  
のメッセージ:

> Conditional conformances
> Proposal: SE-
> Author: Doug Gregor
> Review Manager: TBD
> Status: Awaiting review
> During the review process, add the following fields as needed:
> 
> Decision Notes: Rationale, Additional Commentary
> Bugs: SR-, SR-
> Previous Revision: 1
> Previous Proposal: SE-
> Introduction
> 
> Conditional conformances express the notion that a generic type will conform 
> to a particular protocol only when it's type arguments meet certain 
> requirements. For example, the Array collection can implement the Equatable 
> protocol only when its elements are themselves Equatable, which can be 
> expressed via the following conditional conformance on Equatable:
> 
> extension Array: Equatable where Element: Equatable {
>   static func ==(lhs: Array, rhs: Array) -> Bool { ... }
> }
> This feature is part of the generics manifesto because it's something that 
> fits naturally into the generics model and is expected to have a high impact 
> on the Swift standard library.
> 
> Swift-evolution thread: TBD: Discussion thread topic for that proposal
> 
> Motivation
> 
> Conditional conformances address a hole in the composability of the generics 
> system. Continuing the Array example from above, it's always been the case 
> that one could use the == operator on two arrays of Equatable type, e.g., 
> [Int]() == [Int]() would succeed. However, it doesn't compose: arrays of 
> arrays of Equatable types cannot be compared (e.g.,[Int]== [Int]will fail to 
> compile) because, even though there is an==for arrays of Equatabletype, the 
> arrays themselves are neverEquatable`.
> 
> Conditional conformances are particularly powerful when building generic 
> adapter types, which are intended to reflect the capabilities of their type 
> arguments. For example, consider the "lazy" functionality of the Swift 
> standard library's collections: using the lazy member of a sequence produces 
> a lazy adapter that conforms to the Sequence protocol, while using the lazy 
> member of a collection produces a lazy adapter that conforms to the 
> Collection protocol. In Swift 3, the only way to model this is with different 
> types. For example, the Swift standard library has four similar generic types 
> to handle a lazy collection: LazySequence, LazyCollection, 
> LazyBidirectionalCollection, and LazyRandomAccessCollection. The Swift 
> standard library uses overloading of the lazy property to decide among these:
> 
> extension Sequence {
>   var lazy: LazySequence { ... }
> }
> 
> extension Collection {
>   var lazy: LazyCollection { ... }
> }
> 
> extension BidirectionalCollection {
>   var lazy: LazyBidirectionalCollection { ... }
> }
> 
> extension RandomAccessCollection {
>   var lazy: LazyRandomAccessCollection { ... }
> }
> This approach causes an enormous amount of repetition, and doesn't scale well 
> because each more-capable type has to re-implement (or somehow forward the 
> implementation of) all of the APIs of the less-capable versions. With 
> conditional conformances, one can provide a single generic wrapper type whose 
> basic requirements meet the lowest common denominator (e.g., Sequence), but 
> which scale their capabilities with their type argument (e.g., the 
> LazySequence conforms to Collection when the type argument does, and so on).
> 
> Proposed solution
> 
> In a nutshell, the proposed solution is to allow a constrained extension of a 
> struct, enum, or class to declare protocol conformances. No additional syntax 
> is necessary for this change, because it already exists in the grammar; 
> rather, this proposal removes the limitation that results in the following 
> error:
> 
> t.swift:1:1: error: extension of type 'Array' with constraints cannot have an 
> inheritance clause
> extension Array: Equatable where Element: Equatable { }
> ^~
> Conditional conformances can only be used when the additional requirements of 
> the constrained extension are satisfied. For example, given the 
> aforementioned Array conformance to Equatable:
> 
> func f(_: T) { ... }
> 
> struct NotEquatable { }
> 
> func test(a1: [Int], a2: [NotEquatable]) {
>   f(a1)// okay: [Int] conforms to Equatable because Int conforms to 
> Equatable
>   f(a2)// error: [NotEquatable] does not conform to Equatable because 
> NotEquatable has no conformance to Equatable
> }
> Conditional conformances also have a run-time aspect, because a dynamic check 
> for a protocol conformance might rely on the evaluation of the extra 
> requirements