<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Oct 2, 2016, at 8:56 AM, Callionica (Swift) via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class="">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<T> there are method implementations that check for ICollection<T> 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 <span class=""></span>dynamic dispatch. <br class=""></div></blockquote><div><br class=""></div><div>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.</div><div><br class=""></div><div>-Joe</div><br class=""><blockquote type="cite" class=""><div class="">On Sunday, October 2, 2016, plx via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Sep 30, 2016, at 1:23 PM, Douglas Gregor <<a href="javascript:_e(%7B%7D,'cvml','dgregor@apple.com');" target="_blank" class="">dgregor@apple.com</a>> wrote:</div><div class=""><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class=""><blockquote type="cite" class=""><div class=""><br class=""></div></blockquote><blockquote type="cite" class=""><div style="word-wrap:break-word" class=""><div class="">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`.</div><div class=""><br class=""></div><div class="">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.</div><div class=""><br class=""></div><div class="">- 80% have no real need for overlapping conditional conformances</div><div class="">- 15% might have “elegance gains” but nothing practically-significant</div><div class="">- 5% would *probably* see real gains but are likely not of broad interest</div><div class=""><br class=""></div><div class="">…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.</div></div></blockquote><div class=""><br class=""></div><div class="">Very interesting, thanks for doing this review!</div></div></div></blockquote><div class=""><br class=""></div><div class="">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.</div><div class=""><br class=""></div><div class="">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:</div><div class=""><br class=""></div><div class=""> enum Sum2<A,B> {</div><div class=""> case a(A)</div><div class=""> case b(B)</div><div class=""> }</div><div class=""> </div><div class="">...(and analogously for 3, 4, as-necessary). </div><div class=""><br class=""></div><div class="">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.</div><div class=""><br class=""></div><div class="">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:</div><div class=""><br class=""></div><div class=""> extension Sum2:Equatable where A:Equatable, B:Equatable {</div><div class=""> // details elided</div><div class=""> }</div><div class=""> </div><div class=""> /// Adaptor using `ObjectIdentifier` to implement `==`.</div><div class=""> struct ObjectWrapper<Wrapped:<wbr class="">AnyObject> : Equatable, Hashable {</div><div class=""> let wrapped: Wrapped</div><div class=""> }</div><div class=""> </div><div class="">...as upon reflection I really would prefer dealing with the hassle of working with `Sum2<A,ObjectWrapper<B>>` in situations where -- in theory -- `Sum2<A,B>` 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!). </div><div class=""><br class=""></div><div class="">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:</div><div class=""><br class=""></div><div class=""> protocol WidgetFactory {</div><div class=""> associatedtype Widget</div><div class=""> associatedtype Material</div><div class=""> </div><div class=""> func produceWidget(using material: Material) -> Widget</div><div class=""> }</div><div class=""><br class=""></div><div class="">...then it's rather easy to simply write this type of boilerplate:</div><div class=""><br class=""></div><div class=""> extension ObjectWrapper: WidgetFactory where Wrapped: WidgetFactory {</div><div class=""> typealias Widget = Wrapper.Widget</div><div class=""> typealias Material = Wrapper.Material</div><div class=""> </div><div class=""> func produceWidget(using material: Material) -> Widget {</div><div class=""> return base.produceWidget(using: material)</div><div class=""> }</div><div class=""> }</div><div class=""> </div><div class="">...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:</div><div class=""><br class=""></div><div class=""> extension Sum2: WidgetFactory </div><div class=""> where </div><div class=""> A:WidgetFactory, B:WidgetFactory,</div><div class=""> A.Material == B.Material,</div><div class=""> A.Widget == B.Widget {</div><div class=""> </div><div class=""> typealias Widget = A.Widget</div><div class=""> typealias Material = A.Material</div><div class=""> </div><div class=""> func produceWidget(using material: Material) throws -> Widget {</div><div class=""> switch self {</div><div class=""> case let .a(aa): return aa.produceWidget(using: material)</div><div class=""> case let .b(bb): return bb.produceWidget(using: material)</div><div class=""> }</div><div class=""> }</div><div class=""> </div><div class=""> }</div><div class=""> </div><div class="">...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).</div><div class=""><br class=""></div><div class="">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).</div><div class=""><br class=""></div><div class="">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 conformances...and that after revisiting them expecting to be troubled by the proposed banning of overlapping conformances, I'm now thinking I'd wind up not using the overlapping-conformance approach in such cases even if it were available.</div><div class=""><br class=""></div><div class="">So that's the first 80%.</div><div class=""><br class=""></div><div class="">Moving on, the next 15% are places where there's some forced theoretical or aesthetic inelegance due to the lack of overlapping conformances, but none of these seem to have any significant practical import.</div><div class=""><br class=""></div><div class="">A representative case here is that I currently have the following pair:</div><div class=""><br class=""></div><div class=""> /// `ChainSequence2(a,b)` enumerates the elements of `a` then `b`.</div><div class=""> struct ChainSequence2<A:Sequence,B:<wbr class="">Sequence> : Sequence</div><div class=""> where A.Iterator.Element == B.Iterator.Element {</div><div class=""> // elided</div><div class=""> }</div><div class=""><br class=""></div><div class=""> /// `ChainCollection2(a,b)` enumerates the elements of `a` then `b`.</div><div class=""> struct ChainCollection2<A:Collection,<wbr class="">B:Collection> : Collection</div><div class=""> where A.Iterator.Element == B.Iterator.Element {</div><div class=""> // ^ `where` is not quite right, see below</div><div class=""> }</div><div class=""><br class=""></div><div class="">...and obviously conditional conformances will allow these to be consolidated into a single `Chain2` type that then has appropriate conditional conformances (and for which the cost/benefit for me will tip in favor of adding conditional conformances to `BidirectionalCollection` and `RandomAccessCollection`, also).</div><div class=""><br class=""></div><div class="">On paper--e.g., theoretically--the lack of overlapping conformances leaves in a few aesthetic issues...for example, at present `ChainCollection2` actually has to be one of these:</div><div class=""><br class=""></div><div class=""> // "narrower" option: not all `A`, `B` can necessarily be used together:</div><div class=""> struct ChainCollection2<A:Collection,<wbr class="">B:Collection> : Collection</div><div class=""> where </div><div class=""> A.Iterator.Element == B.Iterator.Element,</div><div class=""> A.IndexDistance == B.IndexDistance {</div><div class=""> typealias IndexDistance = A.IndexDistance</div><div class=""> }</div><div class=""><br class=""></div><div class=""> // "wasteful" option: theoretically in some cases we are "overpaying" and </div><div class=""> // using a stronger `IndexDistance`, but now we can use any `A` and `B`</div><div class=""> struct ChainCollection2<A:Collection,<wbr class="">B:Collection> : Collection</div><div class=""> where A.Iterator.Element == B.Iterator.Element {</div><div class=""> typealias IndexDistance = IntMax</div><div class=""> }</div><div class=""><br class=""></div><div class="">With overlapping conditional conformances you could have both: one conformance that uses base collections' `IndexDistance` when possible, and another that uses `IntMax` when necessary...but without conditional conformances it's necessary to choose between the "narrower" approach or the "wasteful" approach (preserving the status quo).</div><div class=""><br class=""></div><div class="">If you're following along I'm sure you're aware that in this specific case, this "choice" is purely academic (or purely aesthetic)...if you go with the `IntMax` route there's almost always going to be between "no actual difference" and "no measurable difference", so even if it *maybe* feels a bit icky the right thing to do is get over it and stop making a mountain out of an anthill.</div><div class=""><br class=""></div><div class="">Note that I'm well aware that you can choose to see this as a concrete instance of a more-general problem -- that the lack of overlapping conformances would potentially leave a lot of performance on the table due to forcing similar decisions (and in contexts where there *would* be a real difference!) -- but speaking personally I couldn't find very much in my "chores pending availability of conditional conformance" that both (a) fell into this category and (b) had more than "aesthetic" implications. </div><div class=""><br class=""></div><div class="">This brings me to that last 5% -- the handful of things for which overlapping conformances have nontrivial benefits -- and my conclusion here is that these tended to be things I doubt are of general interest.</div><div class=""><br class=""></div><div class="">An example here is that I like to use a function that takes two sequences and enumerates their "cartesian product", with the following adjustments:</div><div class=""><br class=""></div><div class="">- no specific enumeration *ordering* is guaranteed</div><div class="">- does something useful even with infinite, one-shot sequences...</div><div class="">- ...meaning specifically that it will eventual-visit any specific pair (even when one or both inputs are infinite, one-shot)</div><div class=""><br class=""></div><div class="">...(useful for doing unit tests, mostly), which to be done "optimally" while also dotting all the is and crossing all the ts would currently require at least 8 concrete types:</div><div class=""><br class=""></div><div class="">- 4 sequences, like e.g.:</div><div class=""> - UnorderedProductSS2<A:<wbr class="">Sequence, B:Sequence></div><div class=""> - UnorderedProductSC2<A:<wbr class="">Sequence, B:Collection></div><div class=""> - UnorderedProductCS2<A:<wbr class="">Collection, B:Sequence></div><div class=""> - UnorderedProductCC2<A:<wbr class="">Collection, B:Collection></div><div class="">- 4 iterators (one for each of the above)</div><div class=""><br class=""></div><div class="">...since you need to use a different iteration strategy for each (yes you don’t *need* 8 types, but I’m trying to “dott all is, cross all ts” here). </div><div class=""><br class=""></div><div class="">In theory overlapping conditional conformances could be used to cut that down to only 5 types:</div><div class=""><br class=""></div><div class="">- 1 type like `UnorderedProduct<A:Sequence,<wbr class="">B:Sequence>`</div><div class="">- the same 4 iterators from before, each used with the appropriate conformance</div><div class=""><br class=""></div><div class="">...which *is* less code *and* seemingly provides nontrivial gains (the `SS` variant must maintain buffers of the items it's already seen from each underlying sequence, but the others have no such requirement).</div><div class=""><br class=""></div><div class="">But, to be honest, even if those gains are realized, this is the kind of situation I'm perfectly comfortable saying is a "niche" and neither broadly relevant to the majority of Swift developers nor broadly relevant to the majority of Swift code; if overlapping conformances were available I'd use them here, but I'm not going to ask for them just to be able to use them here.</div><div class=""><br class=""></div><div class="">Also, I'm skeptical these gains would be realized in practice: between the proposed "least specialized conformance wins" rule and Swift's existing dispatch rules in generic contexts, it seems like even if overlapping conformances *were* allowed and I *did* use them, I'd still wind up getting dispatched to the pessimal `SS` variant in many cases for which I'd have been hoping for one of the more-optimal versions.</div><div class=""><br class=""></div><div class="">So between the niche-ness of such uses -- and their being 5% or less of what I was hoping to do -- and my skepticism about how dispatch would pan out in practice, I can't get behind fighting for overlapping conformances at this time unless they'd be permanently banned by banning them now.</div><div class=""><br class=""></div><div class="">As already stated, I do think that their absence *will* reveal some *true* pain points, but I think it makes sense to adopt a "wait-and-see" approach here as some more-targeted solution could wind up being enough to address the majority of those future pain points.</div><div class=""><br class=""></div><div class="">These are my more-detailed thoughts after looking at what I was planning to do with conditional conformances once the became available. I realize it doesn't touch on every conceivable scenario and every conceivable use, but I want to reiterate that I did my review expecting to find a bunch of things that I could use as justifications for why Swift absolutely should have overlapping conditional conformances right now...but on actually looking at my plans, I couldn't find anything for which I actually felt that way.</div><div class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class=""><br class=""></div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class=""><span style="white-space:pre-wrap" class="">        </span>- Doug</div></div></blockquote></div><br class=""></div></blockquote>
_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></blockquote></div><br class=""></body></html>