<div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Tue, Sep 12, 2017 at 3:32 AM Vladimir.S &lt;<a href="mailto:svabox@gmail.com">svabox@gmail.com</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 12.09.2017 0:35, Tony Allevato wrote:<br>
&gt;<br>
&gt;<br>
&gt; On Mon, Sep 11, 2017 at 2:05 PM Vladimir.S via swift-evolution<br>
&gt; &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a> &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;&gt; wrote:<br>
&gt;<br>
&gt;     On 11.09.2017 21:55, Thorsten Seitz via swift-evolution wrote:<br>
&gt;      &gt; I think I do understand Haravikk&#39;s argument (actually it seems quite<br>
&gt;     straightforward<br>
&gt;      &gt; to me).<br>
&gt;      &gt;<br>
&gt;      &gt; An example should be:<br>
&gt;      &gt;<br>
&gt;      &gt; struct Foo : Equatable {<br>
&gt;      &gt;      var x: Int<br>
&gt;      &gt;      var cachedLabel: String? = nil<br>
&gt;      &gt;<br>
&gt;      &gt;      init(x: Int) {<br>
&gt;      &gt;          self.x = x<br>
&gt;      &gt;      }<br>
&gt;      &gt;<br>
&gt;      &gt;      mutating func label() {<br>
&gt;      &gt;          if let label = cachedLabel {<br>
&gt;      &gt;              return label<br>
&gt;      &gt;          }<br>
&gt;      &gt;          let label = calculateLabel()<br>
&gt;      &gt;          cachedLabel = label<br>
&gt;      &gt;          return cachedLabel<br>
&gt;      &gt;      }<br>
&gt;      &gt; }<br>
&gt;      &gt;<br>
&gt;      &gt; var foo1 = Foo(x: 1)<br>
&gt;      &gt; var foo2 = Foo(x: 1)<br>
&gt;      &gt; foo1 == foo2 // true<br>
&gt;      &gt; var label = foo1.label()<br>
&gt;      &gt; foo1 == foo2 // now false, due to cachedString being falsely included in the<br>
&gt;     comparison<br>
&gt;      &gt;<br>
&gt;      &gt; The problem is that the developer was not required to implement the protocol<br>
&gt;     and so<br>
&gt;      &gt; might forget it.<br>
&gt;      &gt; The difference to other default implementations is that those use the protocol<br>
&gt;     itself<br>
&gt;      &gt; as building blocks and so are correct with regards to the protocol&#39;s semantics,<br>
&gt;      &gt; whereas the synthesized equality reaches deeply into the private innards of a<br>
&gt;     struct<br>
&gt;      &gt; and therefore is much more likely to be wrong as in the example above.<br>
&gt;      &gt;<br>
&gt;      &gt; Why not just write<br>
&gt;      &gt;<br>
&gt;      &gt; *struct* Foo : *deriving* Equatable {...}<br>
&gt;      &gt;<br>
&gt;      &gt; to request the synthesized implementation?<br>
&gt;<br>
&gt;     FWIW, +100. The same should be required for Codable. I support the opinion that<br>
&gt;     &#39;synthesized&#39; methods differs from protocol-default-implementation in what &#39;kind&#39; of<br>
&gt;     data they use: defined by protocol itself or internals of the conformed type. And<br>
&gt;     this can lead to more un-expected problems.<br>
&gt;<br>
&gt;     If protocol is able to synthesize its requirements, it should require a<br>
&gt;     &#39;deriving&#39;-like marker when type conforms to it to make it absolutely clear what<br>
&gt;     happens here. It would be not a confusion point, but clarify the intention to better<br>
&gt;     understand the code.<br>
&gt;<br>
&gt;     Thinking about *future* custom protocols that could implement requirements in default<br>
&gt;     implementation by using macros/reflection, for me it seems like such protocol should<br>
&gt;     *also* somehow explicitly state that some requirements are auto-synthesized, probably<br>
&gt;     by conforming(derive) to some compiler-magic protocol &#39;AutoSynthesize&#39;.<br>
&gt;     (i.e. &#39;protocol MySynthesizeable: AutoSynthesize {...}&#39;)<br>
&gt;<br>
&gt;     So each built-in protocol like Equatable/Hashable/Codable will conform to it, and<br>
&gt;     also, each custom &quot;auto-synthesizeable&quot; protocol - also should explicitly conform to<br>
&gt;     AutoSynthesize. So, when type conforms to it - such type should use &#39;deriving&#39;-like<br>
&gt;     marker if auto-generation of methods is expected.<br>
&gt;<br>
&gt;<br>
&gt; This doesn&#39;t align with how Swift views the role of protocols, though. One of the<br>
&gt; criteria that the core team has said they look for in a protocol is &quot;what generic<br>
&gt; algorithms would be written using this protocol?&quot; AutoSynthesize doesn&#39;t satisfy<br>
&gt; that—there are no generic algorithms that you would write with AutoEquatable that<br>
&gt; differ from what you would write with Equatable.<br>
&gt;<br>
<br>
OK, got it, it was general thoughts, not exact proposal regarding the AutoSynthesize<br>
protocol. Probably it should be @autosynthesize directive for protocol when you<br>
define it or other &#39;marker&#39;, so when you conform to this protocol, you *can*<br>
explicitely use &#39;derived&#39;-like keyword to make requirements auto-synthesized,<br>
otherwise you&#39;ll be asked by compiler for manual implementation.<br>
<br>
<br>
&gt;     I also have a question regarding future direction of &#39;exclusion&#39; of fields from being<br>
&gt;     included into auto-generated implementation of Equatable/Hashable/Codable/other.<br>
&gt;<br>
&gt;     If we&#39;ll have this &#39;deriving&#39;-like marker, it seems naturally if we mark some member<br>
&gt;     with some kind of &#39;@noderiving&#39; marker, like here:<br>
&gt;<br>
&gt;     struct Foo : deriving Equatable {<br>
&gt;             var x: Int<br>
&gt;             var y: Int<br>
&gt;             var z: Int<br>
&gt;             @noderiving var cachedLabel: String? = nil<br>
&gt;     }<br>
&gt;<br>
&gt;     this @noderiving directive will work for protocols based on AutoSynthesize magic<br>
&gt;     protocol. I.e., if you construct your own protocol with auto-synthesizeable methods,<br>
&gt;     to be able to *know* which members should be &#39;excluded&#39; for your implementation, you<br>
&gt;     should base your protocol on AutoSynthesize protocol.<br>
&gt;<br>
&gt;<br>
&gt; This is something I mention in the original proposal, and I agree that it would be<br>
&gt; nice to have added later since there are clear known use cases where it&#39;s important.<br>
&gt;<br>
&gt; However, the feature shouldn&#39;t be tied *specifically* to derived implementations<br>
&gt; (meaning it shouldn&#39;t be named that way). What we&#39;re really talking about is<br>
&gt; &quot;transient&quot; data—data that exists for the purposes of caching/performance/etc. but<br>
&gt; which does not actually contribute to the thing&#39;s &quot;value&quot;.<br>
&gt;<br>
&gt; The fact that transient data should not be ignored for equality, hashing, and<br>
&gt; serialization just happens to align with the protocols that we auto-synthesize so<br>
&gt; far, but it&#39;s not necessarily limited to those use cases. If an attribute is added<br>
&gt; for something like this, it should be *semantic* rather than speak to implementation<br>
&gt; details. In other words, it would be inappropriate to say &quot;exclude this property from<br>
&gt; synthesized operations&quot;, but it would be fine to say &quot;this property is transient<br>
&gt; data&quot; and it just so happens that Equatable, Hashable, and Codable use that<br>
&gt; information to control what they synthesize.<br>
&gt;<br>
&gt; All this is a subtle, but important, distinction. One day, when Swift has the ability<br>
&gt; to introspect metadata about a type and its properties, someone may want to use a<br>
&gt; hypothetical &quot;transient&quot; attribute for something wholly unrelated to synthesis.<br>
<br>
I see your points, but is it not possible that we want to exclude some property for<br>
Equatable but keep it for Codable, or vise-versa, for example? So, actually, IMO we<br>
need a way to exclude property from some specific protocol/protocols. Like<br>
<br>
@transient var ...<br>
@transient(for:Equatable) var ...<br>
@transient(for:Codable) var ...<br>
@transient(for:SomeOtherAuto) var ...<br>
<br>
And again, I&#39;m not proposing some concrete syntax/keyword, but think we&#39;ll need(in<br>
future,yes, but IMO better to discuss now) a way to &#39;exclude&#39; specific property from<br>
specific auto-synthesizeable protocol.<br></blockquote><div><br></div><div>It&#39;s possible, but we shouldn&#39;t think of it in terms of &quot;exclude from a protocol&quot;. There are some different combinations to consider here:</div><div><br></div><div>* Does it make sense to use a property in a synthesized Hashable but not in the synthesized Equatable? No, because of the contract between those two protocols. Such an exclusion would allow two equal values to hash to different values.</div><div><br></div><div>* Does it make sense to use a property in a synthesized Equatable but not in the synthesized Hashable? Sure; if your data type is large you may only want to hash a subset of its properties. If that&#39;s the case, your hash function is probably simple enough that you can just override the property manually, which is more scalable than tagging all the non-hash properties individually.</div><div><br></div><div>* Does it make sense to exclude a property used by synthesized Equatable/Hashable from synthesized Codable? Sure, maybe. If the property is truly transient cached data then it can easily be recomputed on demand, but you could argue that it&#39;s worth serializing if doing so is more efficient than performing the computation again.</div><div><br></div><div>The key thing to note here is that &quot;transient&quot; shouldn&#39;t mean &quot;exclude from synthesized implementations&quot;. &quot;Transient&quot;, at least as I&#39;m describing it, means &quot;data that does not strictly contribute to something&#39;s notion of its &#39;value&#39;&quot;. That&#39;s a semantic definition and it&#39;s up to the protocols themselves to decide how to interpret it. If there were a need for different &quot;levels&quot; of transience, then the attribute could be extended with more semantic information that lets the protocol decide what to do, or a new attribute could be introduced. The important thing is that you&#39;re saying &quot;what does this property mean and how does it behave&quot;, not &quot;which specific protocols can or can&#39;t do something with this property&quot;.</div><div><br></div><div>Regarding &quot;what about some future protocol&quot;, we can&#39;t really consider those realistically if we don&#39;t know what the semantics of that protocol are.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
Just my 2 cents why I believe we need an explicit &#39;derived&#39;-like keyword when we want<br>
auto-synthesized requirement for protocol:<br>
<br>
* This will not change the logic/behavior of &#39;normal&#39; conformance to<br>
Equatable/Hashable, i.e. if you conform the type to them - you need to provide an<br>
implementation OR (new text in warning message will be added) &quot;use &#39;derived&#39; keyword<br>
to &quot;auto-synthesize&quot; these methods.<br>
I.e. auto-synthesize will be something separate, additional, that you can use if you<br>
want it, your clear choose.<br>
It will not interfere with your &#39;usual&#39; model of protocol conformance.<br>
<br>
* You explicitly mark which protocol you want to be synthesized for you. For example,<br>
if I see &quot;struct S: derived Equatable, Codable&quot; - I understand that Equatable will be<br>
&quot;generated&quot; and Codable will be implemented manually in code.<br>
<br>
* This makes code more clean, more understandable by reader, less error-prone, more<br>
explicit on intention. The code *will* be better.<br>
<br>
* Without explicit &#39;derived&#39;-like keyword, the code will be worse : less explicit<br>
about intention, more error-prone, hiding important details from reader, etc.<br>
<br>
* And the &#39;derived&#39;-like keyword is good price to have better code in this case.<br>
<br>
Just my IMOs. Thank you for reading.<br>
<br>
Vladimir.<br>
<br>
&gt;<br>
&gt;<br>
&gt;     I hope this makes any sense :-)<br>
&gt;<br>
&gt;     Vladimir.<br>
&gt;<br>
&gt;      &gt;<br>
&gt;      &gt; -Thorsten<br>
&gt;      &gt;<br>
&gt;      &gt;<br>
&gt;      &gt; Am 09.09.2017 um 19:42 schrieb Xiaodi Wu via swift-evolution<br>
&gt;      &gt; &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a> &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;<br>
&gt;     &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a> &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;&gt;&gt;:<br>
&gt;      &gt;<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt; On Sat, Sep 9, 2017 at 06:41 Haravikk via swift-evolution<br>
&gt;      &gt;&gt; &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a> &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;<br>
&gt;     &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a> &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;&gt;&gt; wrote:<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;&gt;     On 9 Sep 2017, at 09:33, Xiaodi Wu &lt;<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a><br>
&gt;     &lt;mailto:<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>&gt;<br>
&gt;      &gt;&gt;&gt;     &lt;mailto:<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a> &lt;mailto:<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>&gt;&gt;&gt; wrote:<br>
&gt;      &gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;     On Sat, Sep 9, 2017 at 02:47 Haravikk via swift-evolution<br>
&gt;      &gt;&gt;&gt;     &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a> &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;<br>
&gt;     &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a> &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;&gt;&gt; wrote:<br>
&gt;      &gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;&gt;         On 9 Sep 2017, at 02:02, Xiaodi Wu &lt;<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a><br>
&gt;     &lt;mailto:<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>&gt;<br>
&gt;      &gt;&gt;&gt;&gt;         &lt;mailto:<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a> &lt;mailto:<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>&gt;&gt;&gt; wrote:<br>
&gt;      &gt;&gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;&gt;         On Fri, Sep 8, 2017 at 4:00 PM, Itai Ferber via<br>
&gt;      &gt;&gt;&gt;&gt;         swift-evolution&lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
&gt;     &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;<br>
&gt;      &gt;&gt;&gt;&gt;         &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
&gt;     &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;&gt;&gt;wrote:<br>
&gt;      &gt;&gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;&gt;&gt;             On Sep 8, 2017, at 12:46 AM, Haravikk via swift-evolution<br>
&gt;      &gt;&gt;&gt;&gt;&gt;             &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a> &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;<br>
&gt;     &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a> &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;&gt;&gt; wrote:<br>
&gt;      &gt;&gt;&gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;&gt;&gt;&gt;             On 7 Sep 2017, at 22:02, Itai Ferber &lt;<a href="mailto:iferber@apple.com" target="_blank">iferber@apple.com</a><br>
&gt;     &lt;mailto:<a href="mailto:iferber@apple.com" target="_blank">iferber@apple.com</a>&gt;<br>
&gt;      &gt;&gt;&gt;&gt;&gt;&gt;             &lt;mailto:<a href="mailto:iferber@apple.com" target="_blank">iferber@apple.com</a> &lt;mailto:<a href="mailto:iferber@apple.com" target="_blank">iferber@apple.com</a>&gt;&gt;&gt; wrote:<br>
&gt;      &gt;&gt;&gt;&gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;&gt;&gt;&gt;             |protocol Fooable : Equatable { // Equatable is just a simple<br>
&gt;      &gt;&gt;&gt;&gt;&gt;&gt;             example var myFoo: Int { get } } extension Fooable { static func<br>
&gt;      &gt;&gt;&gt;&gt;&gt;&gt;             ==(_ lhs: Self, _ rhs: Self) -&gt; Bool { return lhs.myFoo ==<br>
&gt;      &gt;&gt;&gt;&gt;&gt;&gt;             rhs.myFoo } } struct X : Fooable { let myFoo: Int let myName:<br>
&gt;      &gt;&gt;&gt;&gt;&gt;&gt;             String // Whoops, forgot to give an implementation of == }<br>
&gt;      &gt;&gt;&gt;&gt;&gt;&gt;             print(X(myFoo: 42, myName: &quot;Alice&quot;) == X(myFoo: 42, myName:<br>
&gt;     &quot;Bob&quot;))<br>
&gt;      &gt;&gt;&gt;&gt;&gt;&gt;             // true|<br>
&gt;      &gt;&gt;&gt;&gt;&gt;&gt;             This property is/necessary/, but not/sufficient/to provide a<br>
&gt;      &gt;&gt;&gt;&gt;&gt;&gt;             correct implementation. A default implementation might be able<br>
&gt;      &gt;&gt;&gt;&gt;&gt;&gt;             to/assume/ something about the types that it defines, but it does<br>
&gt;      &gt;&gt;&gt;&gt;&gt;&gt;             not necessarily know enough.<br>
&gt;      &gt;&gt;&gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;&gt;&gt;             Sorry but that&#39;s a bit of a contrived example; in this case the<br>
&gt;      &gt;&gt;&gt;&gt;&gt;             protocol should*not* implement the equality operator if more<br>
&gt;      &gt;&gt;&gt;&gt;&gt;             information may be required to define equality. It should only be<br>
&gt;      &gt;&gt;&gt;&gt;&gt;             implemented if the protocol is absolutely clear that .myFoo is the<br>
&gt;      &gt;&gt;&gt;&gt;&gt;             only part of a Fooable that can or should be compared as<br>
&gt;     equatable,<br>
&gt;      &gt;&gt;&gt;&gt;&gt;             e.g- if a Fooable is a database record and .myFoo is a primary<br>
&gt;     key,<br>
&gt;      &gt;&gt;&gt;&gt;&gt;             the data could differ but it would still be a reference to the<br>
&gt;     same<br>
&gt;      &gt;&gt;&gt;&gt;&gt;             record.<br>
&gt;      &gt;&gt;&gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;&gt;&gt;             To be clear, I&#39;m not arguing that someone can&#39;t create a regular<br>
&gt;      &gt;&gt;&gt;&gt;&gt;             default implementation that also makes flawed assumptions, but<br>
&gt;     that<br>
&gt;      &gt;&gt;&gt;&gt;&gt;             synthesised/reflective implementations*by their very nature have<br>
&gt;      &gt;&gt;&gt;&gt;&gt;             to*, as they cannot under every circumstance guarantee correctness<br>
&gt;      &gt;&gt;&gt;&gt;&gt;             when using parts of a concrete type that they know nothing about.<br>
&gt;      &gt;&gt;&gt;&gt;             You can’t argue this both ways:<br>
&gt;      &gt;&gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;&gt;               * If you’re arguing this on principle, that in order for<br>
&gt;      &gt;&gt;&gt;&gt;                 synthesized implementations to be correct, they/must/ be<br>
&gt;     able to<br>
&gt;      &gt;&gt;&gt;&gt;                 —/under every circumstance/ — guarantee correctness, then you<br>
&gt;      &gt;&gt;&gt;&gt;                 have to apply the same reasoning to default protocol<br>
&gt;      &gt;&gt;&gt;&gt;                 implementations. Given a default protocol implementation, it is<br>
&gt;      &gt;&gt;&gt;&gt;                 possible to come up with a (no matter how contrived) case where<br>
&gt;      &gt;&gt;&gt;&gt;                 the default implementation is wrong. Since you’re arguing<br>
&gt;     this/on<br>
&gt;      &gt;&gt;&gt;&gt;                 principle/, you cannot reject contrived examples.<br>
&gt;      &gt;&gt;&gt;&gt;               * If you are arguing this/in practice/, then you’re going to have<br>
&gt;      &gt;&gt;&gt;&gt;                 to back up your argument with evidence that synthesized<br>
&gt;     examples<br>
&gt;      &gt;&gt;&gt;&gt;                 are more often wrong than default implementations. You can’t<br>
&gt;      &gt;&gt;&gt;&gt;                 declare that synthesized implementations are/by<br>
&gt;     nature/incorrect<br>
&gt;      &gt;&gt;&gt;&gt;                 but allow default implementations to slide because/in<br>
&gt;     practice/,<br>
&gt;      &gt;&gt;&gt;&gt;                 many implementations are allowable. There’s a reason why<br>
&gt;      &gt;&gt;&gt;&gt;                 synthesis passed code review and was accepted: in the<br>
&gt;     majority of<br>
&gt;      &gt;&gt;&gt;&gt;                 cases, synthesis was deemed to be beneficial, and would provide<br>
&gt;      &gt;&gt;&gt;&gt;                 correct behavior. If you are willing to say that yes, sometimes<br>
&gt;      &gt;&gt;&gt;&gt;                 default implementations are wrong but overall they’re correct,<br>
&gt;      &gt;&gt;&gt;&gt;                 you’re going to have to provide hard evidence to back up the<br>
&gt;      &gt;&gt;&gt;&gt;                 opposite case for synthesized implementations. You stated in a<br>
&gt;      &gt;&gt;&gt;&gt;                 previous email that &quot;A synthesised/reflective implementation<br>
&gt;      &gt;&gt;&gt;&gt;                 however may return a result that is simply incorrect,<br>
&gt;     because it<br>
&gt;      &gt;&gt;&gt;&gt;                 is based on assumptions made by the protocol developer, with no<br>
&gt;      &gt;&gt;&gt;&gt;                 input from the developer of the concrete type. In this case the<br>
&gt;      &gt;&gt;&gt;&gt;                 developer must override it in to provide *correct*<br>
&gt;     behaviour.&quot; —<br>
&gt;      &gt;&gt;&gt;&gt;                 if you can back this up with evidence (say, taking a survey<br>
&gt;     of a<br>
&gt;      &gt;&gt;&gt;&gt;                 large number of model types and see if in the majority of cases<br>
&gt;      &gt;&gt;&gt;&gt;                 synthesized implementation would be incorrect) to provide a<br>
&gt;      &gt;&gt;&gt;&gt;                 compelling argument, then this is something that we should in<br>
&gt;      &gt;&gt;&gt;&gt;                 that case reconsider.<br>
&gt;      &gt;&gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;&gt;         Well put, and I agree with this position 100%. However, to play devil&#39;s<br>
&gt;      &gt;&gt;&gt;&gt;         advocate here, let me summarize what I think Haravikk is saying:<br>
&gt;      &gt;&gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;&gt;         I think the &quot;synthesized&quot; part of this is a red herring, if I<br>
&gt;     understand<br>
&gt;      &gt;&gt;&gt;&gt;         Haravikk&#39;s argument correctly. Instead, it is this:<br>
&gt;      &gt;&gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;&gt;         (1) In principle, it is possible to have a default implementation for a<br>
&gt;      &gt;&gt;&gt;&gt;         protocol requirement that produces the correct result--though not<br>
&gt;      &gt;&gt;&gt;&gt;         necessarily in the most performant way--for all possible conforming<br>
&gt;      &gt;&gt;&gt;&gt;         types, where by conforming we mean that the type respects both the<br>
&gt;      &gt;&gt;&gt;&gt;         syntactic requirements (enforced by the compiler) and the semantic<br>
&gt;      &gt;&gt;&gt;&gt;         requirements (which may not necessarily be enforceable by the compiler)<br>
&gt;      &gt;&gt;&gt;&gt;         of the protocol in question.<br>
&gt;      &gt;&gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;&gt;         (2) However, there exist *some* requirements that, by their very<br>
&gt;     nature,<br>
&gt;      &gt;&gt;&gt;&gt;         cannot have default implementations which are guaranteed to produce the<br>
&gt;      &gt;&gt;&gt;&gt;         correct result for all conforming types. In Haravikk&#39;s view, no default<br>
&gt;      &gt;&gt;&gt;&gt;         implementations should be provided in these cases. (I don&#39;t necessarily<br>
&gt;      &gt;&gt;&gt;&gt;         subscribe to this view in absolute terms, but for the sake of argument<br>
&gt;      &gt;&gt;&gt;&gt;         let&#39;s grant this premise.)<br>
&gt;      &gt;&gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;&gt;         (3) Equatable, Hashable, and Codable requirements are, by their very<br>
&gt;      &gt;&gt;&gt;&gt;         nature, such requirements that cannot have default implementations<br>
&gt;      &gt;&gt;&gt;&gt;         guaranteed to be correct for all conforming types. Therefore, they<br>
&gt;     should<br>
&gt;      &gt;&gt;&gt;&gt;         not have a default implementation. It just so happens that a default<br>
&gt;      &gt;&gt;&gt;&gt;         implementation cannot currently be written in Swift itself and must be<br>
&gt;      &gt;&gt;&gt;&gt;         synthesized, but Haravikk&#39;s point is that even if they could be written<br>
&gt;      &gt;&gt;&gt;&gt;         in native Swift through a hypothetical reflection facility, they should<br>
&gt;      &gt;&gt;&gt;&gt;         not be, just as many other protocol requirements currently could have<br>
&gt;      &gt;&gt;&gt;&gt;         default implementations written in Swift but should not have them<br>
&gt;     because<br>
&gt;      &gt;&gt;&gt;&gt;         they cannot be guaranteed to produce the correct result.<br>
&gt;      &gt;&gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;&gt;         My response to this line of argumentation is as follows:<br>
&gt;      &gt;&gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;&gt;         For any open protocol (i.e., a protocol for which the universe of<br>
&gt;      &gt;&gt;&gt;&gt;         possible conforming types cannot be enumerated a priori by the protocol<br>
&gt;      &gt;&gt;&gt;&gt;         designer) worthy of being a protocol by the Swift standard (&quot;what<br>
&gt;     useful<br>
&gt;      &gt;&gt;&gt;&gt;         thing can you do with such a protocol that you could not<br>
&gt;     without?&quot;), any<br>
&gt;      &gt;&gt;&gt;&gt;         sufficiently interesting requirement (i.e., one for which user<br>
&gt;     ergonomics<br>
&gt;      &gt;&gt;&gt;&gt;         would measurably benefit from a default implementation) either cannot<br>
&gt;      &gt;&gt;&gt;&gt;         have a universally guaranteed correct implementation or has an<br>
&gt;      &gt;&gt;&gt;&gt;         implementation which is also going to be the most performant one (which<br>
&gt;      &gt;&gt;&gt;&gt;         can therefore be a non-overridable protocol extension method rather<br>
&gt;     than<br>
&gt;      &gt;&gt;&gt;&gt;         an overridable protocol requirement with a default implementation).<br>
&gt;      &gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;         You&#39;re close, but still missing key points:<br>
&gt;      &gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;          1. I am not arguing that features like these should*not* be<br>
&gt;     provided, but<br>
&gt;      &gt;&gt;&gt;             that they should*not* be provided implicitly, and that the developer<br>
&gt;      &gt;&gt;&gt;             should actually be allowed to request them. That is exactly what<br>
&gt;     this<br>
&gt;      &gt;&gt;&gt;             proposal is about, yet no matter what I say everyone seems to be<br>
&gt;      &gt;&gt;&gt;             treating me like I&#39;m against these features entirely; *I am not*.<br>
&gt;      &gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;     You are entirely against Equatable having a default implementation for ==.<br>
&gt;      &gt;&gt;&gt;     This is unequivocally stated. Others favor such a default implementation and<br>
&gt;      &gt;&gt;&gt;     feel that in the absence of a way to spell this in Swift itself, it<br>
&gt;     should be<br>
&gt;      &gt;&gt;&gt;     magic for the time being. For the purposes of this argument it really is not<br>
&gt;      &gt;&gt;&gt;     pertinent that you are not also against something else; you&#39;re asking us to<br>
&gt;      &gt;&gt;&gt;     discuss why you are against a particular thing that others are for.<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;     FFS, how much clearer can I make this? *I AM NOT AGAINST THE FEATURE.*<br>
&gt;      &gt;&gt;     *<br>
&gt;      &gt;&gt;     *<br>
&gt;      &gt;&gt;     What I am against is the way in which it is being provided implicitly rather<br>
&gt;      &gt;&gt;     than explicitly, in particular as a retroactive change to existing<br>
&gt;     protocols in<br>
&gt;      &gt;&gt;     a way that introduces potential for bugs that are currently impossible, but<br>
&gt;      &gt;&gt;     also in general.<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt; You are against a default implementation for ==, i.e. an implementation that is<br>
&gt;      &gt;&gt; provided for you if you conform a type to the protocol and do nothing else<br>
&gt;      &gt;&gt; (&quot;implicitly rather than explicitly&quot;), and you are against the default<br>
&gt;      &gt;&gt; implementation being on the existing protocol Equatable (&quot;retroactive<br>
&gt;     change&quot;). So,<br>
&gt;      &gt;&gt; to summarize, what you are against is precisely a default implementation for<br>
&gt;     the ==<br>
&gt;      &gt;&gt; requirement on Equatable.<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt; This is the topic of discussion here; I am attempting to convince you that you<br>
&gt;      &gt;&gt; should be for rather than against these things.<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;&gt;     As repeatedly answered by others, nothing here is specific to synthesized<br>
&gt;      &gt;&gt;&gt;     default implementations, as more powerful reflection will gradually<br>
&gt;     allow them<br>
&gt;      &gt;&gt;&gt;     to be non-synthesised.<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;     And as repeatedly stated by me; I am not treating synthesised vs. run-time<br>
&gt;      &gt;&gt;     reflection any differently, I specifically included both in the original<br>
&gt;     proposal.<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;&gt;     As pointed out very cogently by Itai, you assert but offer no evidence,<br>
&gt;     either<br>
&gt;      &gt;&gt;&gt;     in principle or empirically, that going too far by reflection is worse than<br>
&gt;      &gt;&gt;&gt;     going not far enough without reflection in terms of likelihood of a default<br>
&gt;      &gt;&gt;&gt;     implementation being inappropriate for conforming types.<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;     As I have also repeatedly pointed out it is not an issue of &quot;not going far<br>
&gt;      &gt;&gt;     enough&quot; vs. &quot;going too far&quot;; if a default implementation lacks<br>
&gt;     information then<br>
&gt;      &gt;&gt;     it should not be provided, doing so regardless is a flaw in the protocol<br>
&gt;     design<br>
&gt;      &gt;&gt;     and not something that this proposal attempts to address (as such a thing is<br>
&gt;      &gt;&gt;     likely impossible).<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt; Right, one must consider the semantics of the specific protocol requirement<br>
&gt;     and ask<br>
&gt;      &gt;&gt; whether a reasonable default can be provided for it.<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;     Reflective implementations *necessarily* go too far, because they literally<br>
&gt;      &gt;&gt;     know *nothing* about the concrete type with any certainty, except for the<br>
&gt;      &gt;&gt;     properties that are defined in the protocol (which do not require<br>
&gt;     reflection or<br>
&gt;      &gt;&gt;     synthesis in the first place).<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt; I am confused why you are trying to argue in general terms about the universe of<br>
&gt;      &gt;&gt; all possible default implementations that use reflection. This is necessarily a<br>
&gt;      &gt;&gt; more difficult argument to make, and if it is to be convincing for all default<br>
&gt;      &gt;&gt; implementations it must also be convincing for the two specific protocol<br>
&gt;      &gt;&gt; requirements we are talking about here. Start small:<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt; We have agreed, as a community, that there is a reasonable default implementation<br>
&gt;      &gt;&gt; for Equatable.== when certain conditions are met (for value types only at the<br>
&gt;      &gt;&gt; moment, I believe). Namely, given two values of a type that has only Equatable<br>
&gt;      &gt;&gt; stored properties, those values are equal if their stored properties are all<br>
&gt;     equal.<br>
&gt;      &gt;&gt; The author of a new value type who wishes to make her type Equatable but chooses<br>
&gt;      &gt;&gt; not to implement a custom == then benefits from this default when all stored<br>
&gt;      &gt;&gt; properties are Equatable.<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;     And precisely what kind of &quot;evidence&quot; am I expected to give? This is a set of<br>
&gt;      &gt;&gt;     features that *do not exist yet*, I am trying to argue in favour of an<br>
&gt;     explicit<br>
&gt;      &gt;&gt;     end-developer centric opt-in rather than an implicit protocol designer<br>
&gt;     centric<br>
&gt;      &gt;&gt;     one. Yet no-one seems interested in the merits of allowing developers to<br>
&gt;     choose<br>
&gt;      &gt;&gt;     what they want, rather than having implicit behaviours appear potentially<br>
&gt;      &gt;&gt;     unexpectedly.<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt; Both options were examined for Codable and for Equatable/Hashable. The community<br>
&gt;      &gt;&gt; and core team decided to prefer the current design. At this point, new insights<br>
&gt;      &gt;&gt; that arise which could not be anticipated at the time of review could prompt<br>
&gt;      &gt;&gt; revision. However, so far, you have presented arguments already considered during<br>
&gt;      &gt;&gt; review.<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;&gt;     Therefore, your argument reduces to one about which default implementations<br>
&gt;      &gt;&gt;&gt;     generally ought or ought not to be provided--that is, that they ought to be<br>
&gt;      &gt;&gt;&gt;     provided only when their correctness can be guaranteed for all (rather than<br>
&gt;      &gt;&gt;&gt;     almost all) possible conforming types. To which point I sketched a<br>
&gt;     rebuttal above.<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;     If a protocol defines something, and creates a default implementation based<br>
&gt;      &gt;&gt;     only upon those definitions then it must by its very nature be correct. A<br>
&gt;      &gt;&gt;     concrete type may later decided to go further, but that is a feature of the<br>
&gt;      &gt;&gt;     concrete type, not a failure of the protocol itself which can function<br>
&gt;      &gt;&gt;     correctly within the context it created. You want to talk evidence, yet there<br>
&gt;      &gt;&gt;     has been no example given that proves otherwise; thus far only Itai has<br>
&gt;      &gt;&gt;     attempted to do so, but I have already pointed out the flaws with that<br>
&gt;     example.<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;     The simple fact is that a default implementation may either be flawed or not<br>
&gt;      &gt;&gt;     within the context of the protocol itself; but a reflective or synthetic<br>
&gt;      &gt;&gt;     implementation by its very nature goes beyond what the protocol defines<br>
&gt;     and so<br>
&gt;      &gt;&gt;     is automatically flawed because as it does not rely on the end-developer to<br>
&gt;      &gt;&gt;     confirm correctness, not when provided implicitly at least.<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt; Again, if it applies generally, it must apply specifically. What is<br>
&gt;     &quot;automatically<br>
&gt;      &gt;&gt; flawed&quot; about the very reasonable synthesized default implementation of ==?<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;&gt;         And all of this continues to be a side-issue to the fact that in the<br>
&gt;      &gt;&gt;&gt;         specific case of Equatable/Hashable, which thus far has gone ignored, is<br>
&gt;      &gt;&gt;&gt;         that bolting this on retroactively to an existing protocol*hides bugs*.<br>
&gt;      &gt;&gt;&gt;         The issue of reflective default implementations is less of a concern on<br>
&gt;      &gt;&gt;&gt;         very clearly and well defined*new* protocols, though I still prefer<br>
&gt;     more,<br>
&gt;      &gt;&gt;&gt;         rather than less, control, but in the specific case of*existing*<br>
&gt;     protocols<br>
&gt;      &gt;&gt;&gt;         this fucking about with behaviours is reckless and foolish in the<br>
&gt;     extreme,<br>
&gt;      &gt;&gt;&gt;         yet no-one on the core teams seems willing or able to justify it, which<br>
&gt;      &gt;&gt;&gt;         only opens much wider concerns (how am I to have any faith in Swift&#39;s<br>
&gt;      &gt;&gt;&gt;         development if the core team can&#39;t or won&#39;t justify the creation of new<br>
&gt;      &gt;&gt;&gt;         bugs?).<br>
&gt;      &gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;<br>
&gt;      &gt;&gt;&gt;     This has emphatically not gone ignored, as I have myself responded to this<br>
&gt;      &gt;&gt;&gt;     point in an earlier thread in which you commented, as well as many others.<br>
&gt;      &gt;&gt;&gt;     Crucially, no existing conforming type changes its behavior, as they<br>
&gt;     have all<br>
&gt;      &gt;&gt;&gt;     had to implement these requirements themselves. And as I said to you<br>
&gt;     already,<br>
&gt;      &gt;&gt;&gt;     the addition of a synthesized default implementation no more &quot;hides bugs&quot;<br>
&gt;      &gt;&gt;&gt;     going forward than the addition of a non-synthesized default<br>
&gt;     implementation to<br>
&gt;      &gt;&gt;&gt;     an existing protocol, and we do that with some frequency without even Swift<br>
&gt;      &gt;&gt;&gt;     Evolution review.<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;     Feel free to a supply a non-synthesised default implementation for Equatable<br>
&gt;      &gt;&gt;     without the use of reflection. Go-on, I&#39;ll wait.<br>
&gt;      &gt;&gt;     You insist on suggesting these are the same thing, yet if you can&#39;t<br>
&gt;     provide one<br>
&gt;      &gt;&gt;     then clearly they are not.<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt; That is not the argument. The argument is that they are indistinguishable in the<br>
&gt;      &gt;&gt; sense that the author of a type who intends to supply a custom implementation but<br>
&gt;      &gt;&gt; neglects to do so will have a default implementation supplied for them. It is<br>
&gt;      &gt;&gt; plainly true that this is no more or less likely to happen simply because the<br>
&gt;      &gt;&gt; default implementation is synthesized.<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;&gt;     Put another way, what the proposal about synthesizing implementations for<br>
&gt;      &gt;&gt;&gt;     Equatable and Hashable was about can be thought of in two parts: (a) should<br>
&gt;      &gt;&gt;&gt;     there be default implementations; and (b) given that it is impossible to<br>
&gt;     write<br>
&gt;      &gt;&gt;&gt;     these in Swift, should we use magic? Now, as I said above, adding default<br>
&gt;      &gt;&gt;&gt;     implementations isn&#39;t (afaik) even considered an API change that requires<br>
&gt;      &gt;&gt;&gt;     review on this list. Really, what people were debating was (b), whether<br>
&gt;     it is<br>
&gt;      &gt;&gt;&gt;     worth it to implement compiler-supported magic to make these possible. Your<br>
&gt;      &gt;&gt;&gt;     disagreement has to do with (a) and not (b).<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;     Wrong. The use of magic in this case produces something else entirely; that&#39;s<br>
&gt;      &gt;&gt;     the whole point. It is *not the same*, otherwise it wouldn&#39;t be needed at<br>
&gt;     all.<br>
&gt;      &gt;&gt;     It doesn&#39;t matter if it&#39;s compiler magic, some external script or a native<br>
&gt;      &gt;&gt;     macro, ultimately they are all doing something with a concrete type that is<br>
&gt;      &gt;&gt;     currently not possible.<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;     And once again; *I am not arguing against a default implementation that cuts<br>
&gt;      &gt;&gt;     boilerplate*, I am arguing against it being implicit. What I want is to<br>
&gt;     be the<br>
&gt;      &gt;&gt;     one asking for it, because it is not reasonable to assume that just<br>
&gt;     throwing it<br>
&gt;      &gt;&gt;     in there is always going to be fine, because it quite simply is not.<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt; If you have to ask for it, then it&#39;s not a default. You *are* against a default<br>
&gt;      &gt;&gt; implementation.<br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt;     _______________________________________________<br>
&gt;      &gt;&gt;     swift-evolution mailing list<br>
&gt;      &gt;&gt; <a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a> &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;<br>
&gt;     &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a> &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;&gt;<br>
&gt;      &gt;&gt; <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
&gt;      &gt;&gt;<br>
&gt;      &gt;&gt; _______________________________________________<br>
&gt;      &gt;&gt; swift-evolution mailing list<br>
&gt;      &gt;&gt; <a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a> &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;<br>
&gt;     &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a> &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;&gt;<br>
&gt;      &gt;&gt; <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
&gt;      &gt;<br>
&gt;      &gt;<br>
&gt;      &gt; _______________________________________________<br>
&gt;      &gt; swift-evolution mailing list<br>
&gt;      &gt; <a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a> &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;<br>
&gt;      &gt; <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
&gt;      &gt;<br>
&gt;     _______________________________________________<br>
&gt;     swift-evolution mailing list<br>
&gt;     <a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a> &lt;mailto:<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;<br>
&gt;     <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
&gt;<br>
</blockquote></div></div>