<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 Sep 29, 2016, at 11:12 AM, Douglas Gregor <<a href="mailto:dgregor@apple.com" class="">dgregor@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><div class=""><br class="Apple-interchange-newline">On Sep 28, 2016, at 9:48 PM, Russ Bishop <<a href="mailto:xenadu@gmail.com" class="">xenadu@gmail.com</a>> wrote:</div><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div dir="auto" class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class=""><br class=""></div><div class="">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.</div></div></div></div></div></blockquote><div class=""><br class=""></div><div class="">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.</div></div></div></blockquote><div><br class=""></div><div>Yeah your description is already sounding like a lot of work :)</div><div><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div dir="auto" class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class="">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?<span class="Apple-converted-space"> </span></div></div></div></div></div></blockquote><div class=""><br class=""></div><div class="">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.</div></div></div></blockquote><div><br class=""></div><div>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. </div><div><br class=""></div><div>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.</div><div><br class=""></div><div><br class=""></div><div><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div dir="auto" class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class="">What would be the problem with allowing multiple conformances to Equatable so long as the constraints are disjoint<span class="Apple-converted-space"> </span></div></div></div></div></div></blockquote><div class=""><br class=""></div><div class="">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”.</div></div></div></blockquote><div><br class=""></div><div>Yes, I was also imagining protocols so long as there is no protocol they share in common except the empty protocol.</div><div><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class=""><br class=""></div><div class="">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.</div></div></div></blockquote><div><br class=""></div><div>That’s Bad ™️</div><div><br class=""></div><div><br class=""></div><div><br class=""></div><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class="">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.</div></div></div></blockquote><div><br class=""></div><div>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. </div><div><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div dir="auto" class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class="">or the concrete type only adopts one of the available protocols?</div></div></div></div></div></blockquote><div class=""><br class=""></div><div class="">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.</div></div></div></blockquote><div><br class=""></div><div>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.</div><div><br class=""></div><div>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 <font face="Menlo" class="">Array: ProtobufMessage where Element: GSMSEntityProtocol</font> but I was able to provide <font face="Menlo" class="">Array: ProtobufMessage where Element: MyOwnProtocol</font>. </div><div><br class=""></div><div><br class=""></div><div>That said the restrictions can always be relaxed later. I’d rather have this feature without overlapping conformances than not have it.</div><div><br class=""></div><div><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div dir="auto" class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><p class="" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(51, 51, 51); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);">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:</p><div class="highlight highlight-source-swift" style="box-sizing: border-box; margin-bottom: 16px; color: rgb(51, 51, 51); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);"><pre class="" style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; margin-top: 0px; margin-bottom: 0px; line-height: 1.45; word-wrap: normal; padding: 16px; overflow: auto; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal;"><span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">struct</span> X4<span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);"><</span>T<span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">></span> { }
<span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">extension</span> X4: Q <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">where</span> T: Q { } <span class="pl-c" style="box-sizing: border-box; color: rgb(150, 152, 150);">// implies conformance to P</span>
<span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">extension</span> X4: R <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">where</span> T: R { } <span class="pl-c" style="box-sizing: border-box; color: rgb(150, 152, 150);">// error: implies overlapping conformance to P</span></pre></div><p class="" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(51, 51, 51); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);">Both of these constrained extensions imply a conformance to <code class="" style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;">P</code>, but the actual <code class="" style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;">P</code> implied conformances to <code class="" style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;">P</code> are overlapping and, therefore, result in an error.</p></div></div></blockquote><div class="">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)? </div></div></div></div></div></blockquote><div class=""><br class=""></div><div class="">A conformance to P introduced by the first extension would not be usable by the second extension, because the conformance to P introduced by the first extension might depend on details of “T: Q”… and the second extension can’t assume that “T: Q”.</div></div></div></blockquote><div><br class=""></div><div>What I’m saying is that if T: Q then the entire implementation of P must come from the first extension. If T: R then the entire implementation of P must come from the second extension. If T: P then neither extension applies because there are overlapping extensions. Basically if there is any overlap then the compiler only considers explicit extensions that match without ambiguity, otherwise the extension is ignored. </div><div><br class=""></div><div>func takes<Value: P>(value: Value) { }</div><div><br class=""></div><div>struct CQ: Q { }</div><div>struct CR: R { }</div><div>struct CP: P { }</div><div><br class=""></div><div>takes(X4<CQ>()) //fine, uses first extension</div><div>takes(X4<CR>()) //fine, uses second extension </div><div>takes(X4<CP>()) //error: ambiguous conformance<span class="Apple-tab-span" style="white-space:pre">        </span></div><div><br class=""></div><div><br class=""></div><div><br class=""></div><div>This relates to the disjoint discussion above:</div><div><br class=""></div><div>extension X4: P where T: P { } //error: ambiguous conformance</div><div><br class=""></div><div>Even though there is technically a conformance to P available we just ignore it. Seems like this would be knowable statically by looking at the extensions and the protocol relationships in the constraints?</div><div><br class=""></div><br class=""><blockquote type="cite" class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div dir="auto" class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class=""><br class=""></div></div></div></div></div></blockquote></div></blockquote><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div dir="auto" class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class="">What is the rationale for picking the least specialized extension? That’s not what I would naively expect to happen. If T: R & S then I would expect the more specialized S:R implementation to be preferred, and the explicit R implementation to kick in when T: R. </div></div></div></div></div></blockquote><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">We have to pick the least-specialized extension, because it’s the only one that works. If you pick a more-specialized extension to realize the implied conformance to P, the less-specialized extension doesn’t have a conformance to P that it can rely on.</div></div></blockquote><div><br class=""></div><div>That’s what I was trying to address by saying no mix-n-match. If you’re going to wonder into overlapping territory you must supply two entirely separate implementations of P, one explicit and one inside the Q extension. (I fully admit that might not help the implementation complexity - I don’t know enough about the type checker to answer that).</div><br class=""><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">I’ll see about clarifying the proposal here, because the choice of (unique) least-specialized isn’t arbitrary: it’s the only answer that provides a correct result without introducing overlapping conformances.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>- Doug</div></div></blockquote><br class=""></div><div><br class=""></div><div>Thanks for your work on this proposal!</div><div><br class=""></div><div>Russ</div><div><br class=""></div><div><br class=""></div><br class=""></body></html>