<div dir="ltr">On Fri, Aug 26, 2016 at 6:35 AM, Pyry Jahkola <span dir="ltr">&lt;<a href="mailto:pyry.jahkola@iki.fi" target="_blank">pyry.jahkola@iki.fi</a>&gt;</span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word"><div>Hi Xiaodi and Charles,</div><span class=""><div><br><blockquote type="cite"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>As I said, this discussion has already happened several times. I&#39;m literally just repeating what people said eight months ago, six months ago, and four months ago. There&#39;s not a good answer to this and perhaps several other issues, which is why I don&#39;t see a way forward for the proposal. After all, I was the one proposing the same idea last winter, so I&#39;ve had a few months to think about it.</div></div></div></div></blockquote></div><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><br></div></div></div></div></div></span><div>I&#39;ve been following the discussion from the side both now and before. Without being able to cover everything that&#39;s been said, I hope this message brings at least a bit of new air into the discussion.</div><div><br></div><div>— — —</div><div><br></div><div>Here&#39;s one more approach that, AFAICT, would enable both retroactive modelling and fairly good error diagnostics: <b>bring the full protocol conformance together with a dedicated definition block</b> which can both define implementations and refer to implementations defined elsewhere.</div></div></blockquote><div> </div><div>This is a very well explained proposal. Thanks for taking the time to write it out. But I don&#39;t think it solves the problem, and I&#39;ll respond inline.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word"><div></div><div><b>Details:</b></div><div><br></div><div>1. Allow marking the conformance to a given protocol with a block of code. This could be nested inside a struct/enum/class body or its extension:</div><div><br></div><div><font face="Menlo">    <b>struct</b> Vector {</font></div><div><font face="Menlo">      <b>conformance</b> Hashable { </font><span style="color:rgb(145,145,145);font-family:Menlo">/* TBD, read on… */</span><font face="Menlo"> }</font></div><div><font face="Menlo">    }</font></div><div><font face="Menlo">    <b>extension</b> Vector {</font></div><div><font face="Menlo">      <b>conformance</b> CustomStringConvertible { </font><span style="color:rgb(145,145,145);font-family:Menlo">/* … */</span><font face="Menlo"> }</font></div><div><div><font face="Menlo">    }</font></div></div></div></blockquote><div><br></div><div>In general, I think there is an opposition to organizing nested blocks of members like this (there was strong opposition to proposals for access level grouping, for instance). But besides that somewhat subjective opinion, there might also be difficulty in terms of `private` scoping. These are minor, more speculative points.</div><div><br></div><div>Mainly, I think it is confusing because it looks like a nested type and invites proposals to namespace protocol conforming members (i.e. `Vector.Hashable.hashValue`), which is not what is going on and definitely not the direction in which I would want to take this proposal.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word"><div></div><div>or at the top level, as a clearly marked <i>single-conformance extension</i>:</div><div><br></div><div><font face="Menlo">    <b>conformance</b> Vector : CustomDebugStringConvertible { </font><span style="color:rgb(145,145,145);font-family:Menlo">/* … */</span><font face="Menlo"> }</font></div></div></blockquote><div><br></div><div>This is an improvement. But, you are introducing a second keyword, `conformance` without justification. The same purpose that you outline later could be served by the existing spelling `extension Vector : CustomDebugStringConvertible`, and this has been proposed earlier in this thread and also in previous threads.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word"><div></div><div>2. Inside the body of that block, all protocol (non-extension) methods <b>must</b> be marked with `override`. That includes both the required interface and the customisable interface with library-provided default implementations:</div><div><br></div><div><div><font face="Menlo">    <b>struct</b> Vector {</font></div><div><font face="Menlo">      <b>conformance</b> Hashable {</font></div><div><font face="Menlo">        <b>override static func</b> ==(lhs: <b>Self</b>, rhs: <b>Self</b>) -&gt; Bool { <font color="#919191">/* … */</font> }</font></div><div><font face="Menlo" color="#919191">        // Ok.</font></div><div><font face="Menlo"><br></font></div><div><font face="Menlo">        <font color="#ff2600"><b>var</b> hashValue: Int</font> { </font><span style="color:rgb(145,145,145);font-family:Menlo">/* … */</span><font face="Menlo"> }</font></div><div><font face="Menlo">        <font color="#919191">// </font><b><font color="#ff2600">error:</font></b><font color="#919191"> property &#39;hashValue&#39; is required by Hashable.</font></font></div><div><font face="Menlo" color="#919191">        // (Fixit: mark with &#39;override&#39;)</font></div><div><font face="Menlo"><br></font></div><div><font face="Menlo">        <font color="#ff2600"><b>override static func</b> &lt; (lhs: <b>Self</b>, rhs: <b>Self</b>) -&gt; Bool</font> { </font><span style="color:rgb(145,145,145);font-family:Menlo">/* … */</span><font face="Menlo"> }</font></div><div><font face="Menlo">        <font color="#919191">// </font><b><font color="#ff2600">error:</font></b><font color="#919191"> protocol Hashable does not require &#39;static func &lt;&#39;.</font></font></div><div><font face="Menlo" color="#919191">        // (Fixit #1: remove override. Etc.)</font></div><div><font face="Menlo">      }</font></div><div><font face="Menlo">    }</font></div></div></div></blockquote><div><br></div><div>This is similar to a previous proposal that any member declared in extensions that add a conformance must, if that member has the same or greater visibility than the lesser of the type and protocol, implement a protocol requirement. However, in your proposal, there&#39;s a pervasive requirement for `override`, which adds noise but doesn&#39;t provide an advantage over that alternative proposal. Moreover, I have a problem with your proposed spelling: if there is no default implementation, why should an implementation be said to `override` anything?</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word"><div></div><div>3. When conformance is made explicit as described above, no other part of code is allowed to interfere with that type&#39;s conformance to the protocol under question:</div><div><br></div><div><div><div><span style="font-family:Menlo">    </span><b style="font-family:Menlo">conformance</b><span style="font-family:Menlo"> </span><span style="font-family:Menlo">Vector : Collection {</span></div></div></div><div><font face="Menlo">      <b>override var </b>startIndex: Int { <b>return</b> 0 }</font></div><div><font face="Menlo">      </font><b style="font-family:Menlo">override </b><b style="font-family:Menlo">var</b><span style="font-family:Menlo"> endIndex: Int { </span><b style="font-family:Menlo">return</b><span style="font-family:Menlo"> _count }</span></div><div><font face="Menlo">      </font><b style="font-family:Menlo">override </b><b style="font-family:Menlo">subscript</b><span style="font-family:Menlo">(index: Int) -&gt; Double { </span><b style="font-family:Menlo">return</b><span style="font-family:Menlo"> _elements[index] }</span></div><div><font face="Menlo">      </font><b style="font-family:Menlo">override </b><b style="font-family:Menlo">func</b><span style="font-family:Menlo"> index(after i: Int) -&gt; Int { </span><b style="font-family:Menlo">return</b><span style="font-family:Menlo"> i + 1 }</span></div><div><font face="Menlo">    }</font></div><div><font face="Menlo">    <b>extension</b> Vector {</font></div><div><font face="Menlo">      <font color="#ff2600"><b>var</b> count: Int</font> { <b>return</b> _count }</font></div><div><font face="Menlo">      <font color="#919191">// </font><b><font color="#ff2600">error:</font></b><font color="#919191"> property &#39;count&#39; was introduced by explicit conformance </font></font><span style="color:rgb(145,145,145);font-family:Menlo">to Collection.</span></div><div><font face="Menlo"><font color="#919191">      // (Fixit: Add explicit override to the conformance block.)</font></font></div><div><font face="Menlo">    }</font></div></div></blockquote><div><br></div><div>I&#39;m not sure what safety is gained by this particular rule. The language should make the most simple cases the most straightforward. In the scenario where a struct S, with only a small number of methods, conforms to protocol P, which has only a small number of requirements and no default implementations, it is not confusing at all to put all requirements in the same block of code. Your proposed syntax, if made mandatory [see below about mandatory vs. optional], would greatly increase the visual clutter and difficulty of correctly conforming one simple struct to one simple protocol.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word"><div></div><div>4a. When using a `conformance` block for retroactive modelling, or to explicitly include methods, properties etc. defined elsewhere, it is enough to list those in the body of the `conformance` block:</div><div><br></div><div><div><font face="Menlo">    <b>protocol</b> CountHaving {</font></div></div><div><font face="Menlo">      <b>associatedtype</b> Count : Integer</font></div><div><font face="Menlo">      <b>var</b> count: Count</font></div><div><font face="Menlo">    }</font></div><div><font face="Menlo">    <b>conformance</b> Array : HasCount {</font></div><div><font face="Menlo">      <b>override var</b> count: Int <font color="#919191">// Ok, explicit retroactive modelling.</font></font></div><div><font face="Menlo">    }</font></div></div></blockquote><div><br></div><div>This might be unworkable for certain types of retroactive modeling. If I add a new default implementation to a requirement of `Collection`, I would have to write out conformance statements for *every single Collection type* in the standard library, probably Foundation and Dispatch also, plus any other libraries I use, in addition to my own Collection types. The only way to solve this issue, as far as I can tell, is to say that none of these keywords are required across module boundaries, which carves out an exception (which might be justifiable, but it&#39;s still an exception to the rule).</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word"><div></div><div>4b. Any override declarations without a body within an explicit `conformance` block are requirements for the definitions to exist elsewhere. That includes overridden properties without getters and setters. For example, here&#39;s an alternative way of fixing the error in #4:</div><div><br></div><div><span style="font-family:Menlo">    </span><b style="font-family:Menlo">conformance</b><span style="font-family:Menlo"> </span><span style="font-family:Menlo">Vector : Collection {</span></div><div><font face="Menlo">      <b>override var </b>startIndex: Int { <b>return</b> 0 }</font></div><div><font face="Menlo">      </font><b style="font-family:Menlo">override </b><b style="font-family:Menlo">var</b><span style="font-family:Menlo"> endIndex: Int { </span><b style="font-family:Menlo">return</b><span style="font-family:Menlo"> _count }</span></div><div><font face="Menlo">      </font><b style="font-family:Menlo">override </b><b style="font-family:Menlo">subscript</b><span style="font-family:Menlo">(index: Int) -&gt; Double { </span><b style="font-family:Menlo">return</b><span style="font-family:Menlo"> _elements[index] }</span></div><div><font face="Menlo">      </font><b style="font-family:Menlo">override </b><b style="font-family:Menlo">func</b><span style="font-family:Menlo"> index(after i: Int) -&gt; Int { </span><b style="font-family:Menlo">return</b><span style="font-family:Menlo"> i + 1 }</span></div><div><span style="font-family:Menlo">      <b>override var</b> count: Int <font color="#919191">// No body; defined elsewhere.</font></span></div><div><font face="Menlo">    }</font></div><div><font face="Menlo">    <b>extension</b> Vector {</font></div><div><font face="Menlo">      <b>var</b> count: Int { <b>return</b> _count } <font color="#919191">// Ok.</font></font></div><div><span style="font-family:Menlo">    }</span></div></div></blockquote><div><br></div><div>This is clever, but also confusing (IMO) because you&#39;ve now introduced more than one way of splitting up code that fulfills protocol requirements, when your stated goal is to improve the situation by putting all requirements in the same place.</div><div><br></div><div>Although you&#39;ve insisted on a central location where there&#39;s a catalog of overrides, it might increase rather than decrease confusion about where these requirements are being implemented, because now there&#39;s at least two declarations. For derived classes that conform to protocols but inherit their implementation from a base class, there are additional difficulties: Does `override` mean you&#39;re overriding the base class implementation, or are you using `override` to say that the base class implementation (which you&#39;re not overriding in the derived class) should override the protocol&#39;s default implementation? Also, even though I see a declaration of a protocol requirement with no body, I might not find the implementation anywhere in the derived class, because it&#39;s in another file, and I may not even have access to that source code. In general, it&#39;s exceedingly weird that the derived class would have to re-declare an inherited method with the word `override`, then never override or mention that method again.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word"><div></div><div>5. Just like any other extensions, `conformance` blocks could introduce other non-`override` methods etc. to its needs, but they probably should keep it at minimum.</div></div></blockquote><div><br></div><div>As mentioned earlier, I think a more preferable and terse rule was proposed earlier, where extensions that add conformance are not allowed to have public members (or members equal or more visible than the protocol or type) that don&#39;t implement a requirement.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word"><div>— — —</div><div><br></div><div><b>Downsides. </b>Now, there are obvious reasons not to introduce this complexity to the language:</div><div><br></div><div>− It adds quite a bit of boilerplate to the conformance definition. (OTOH, programmers in a hurry would still be able to use the existing implicit conformance syntax, thereby avoiding the boilerplate on the one hand, and the better diagnostics on the other.)</div></div></blockquote><div><br></div><div>It does add quite a bit of boilerplate; the idea of having this boilerplate has been pitched before, though not with the `conformance` keyword. It&#39;s not great, but it might not in and of itself be a deal-breaker.</div><div><br></div><div>However, the key weakness here IMO is that you are trying to address the weaknesses above by saying that this whole new syntax is _optional_. This is, IMO, a critical flaw. I could _maybe_ get behind a single opt-in keyword or attribute; but I think a whole new alternative syntax for something as fundamental as conformance is a non-starter. This is a very, very essential part of Swift; there should be *one* syntax for protocol conformance, not two. We should find the one best syntax, though obviously we are now constrained by backwards compatibility issues.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word"><div>− It would make it harder to add new required methods with default implementations without breaking code elsewhere. Because explicitly conforming types which already happened to have a matching function, property, or subscript would need to include it in the explicit conformance block. (OTOH, maybe that&#39;s what they indeed asked for by making the conformance explicit!)</div><div><br></div><div>− It would add yet another keyword to the language, context-specific but regardless. And the amount of `override` noise isn&#39;t looking very pretty.</div></div></blockquote><div><br></div><div>Yes, these two weaknesses are definitely issues. In general, from the perspective of library evolution, there&#39;s a key question to be answered: if the library vendor adds a new default implementation to a protocol, should they need to be concerned that it could cause existing code using a previous version of the library to stop compiling?</div><div><br></div><div>Currently, the answer is no, and I think it is the right answer most (if not all) of the the time. I have this opinion because types that conform to the protocol using a previous version of the library cannot possibly change their behavior if a new default implementation is supplied, since these types necessarily have their own implementation of the same requirement and since protocol requirements are dynamically dispatched and there&#39;s no way to break that encapsulation. Therefore, it is unnecessarily disruptive to stop compiling that code in order to force the end user to acknowledge a change that cannot have any effect on their own code. I conclude that any keyword should be _optional_ (if you _want_ your code to break unnecessarily, I guess that can be up to you...), but then see above about my reasoning regarding an optional syntax for protocol conformance.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word"><div>− It possibly complicates some other convenient use of protocols that I can&#39;t think of right now. Discuss.</div><div><br></div><div><b>On the plus sides,</b></div><div><br></div><div>+ There are precedents of explicit conformances in other languages: <a href="https://en.wikibooks.org/wiki/Haskell/Classes_and_types#Classes_and_instances" target="_blank">Haskell&#39;s type classes</a> and <a href="http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/extend" target="_blank">Clojure&#39;s protocols</a> come to mind as most similar.</div><div><br></div><div>+ It better documents how exactly the type conforms to the protocol, without leaving any missing &quot;magic&quot; elsewhere in the codebase. And it would become a compiler-enforced way to the already existing practice of keeping a conformance interface together within an extension block.</div><div><br></div><div><b>Alternatives to consider:</b></div><div><br></div><div>A. Instead of nesting `conformance ProtocolName`, we could say `conformance Self : ProtocolName`.</div><div><br></div><div>B. Instead of introducing a new keyword `conformance` for top-level single-conformance extensions, we could state that `private/internal/public` in front of the `extension` keyword is used to define an explicit conformance of one protocol:</div><div><br></div><div><b style="font-family:Menlo">    internal extension</b><span style="font-family:Menlo"> </span><span style="font-family:Menlo">Vector : Collection { <font color="#919191">/* just Collection things */</font> }</span></div><span class=""><font color="#888888"><div><br></div><div>— Pyry</div><div><br></div></font></span></div></blockquote></div><br></div></div>