<div dir="ltr">Tony makes an excellent point, and I agree. At some point in the future we should consider introducing a “transient” attribute for caches and other non-essential properties. That will make generated conformances more powerful while simultaneously reducing boilerplate.<div><div><br></div><div>Nevin<div><br><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Sep 12, 2017 at 10:39 AM, Tony Allevato via swift-evolution <span dir="ltr">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><br><br><div class="gmail_quote"><span class=""><div dir="ltr">On Mon, Sep 11, 2017 at 10:05 PM Gwendal Roué &lt;<a href="mailto:gwendal.roue@gmail.com" target="_blank">gwendal.roue@gmail.com</a>&gt; wrote:</div></span><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class=""><div style="word-wrap:break-word"><div><blockquote type="cite"><div><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div></div></div></blockquote></div></div></div></blockquote></div></div><div style="word-wrap:break-word"><div><br></div></div></span><div style="word-wrap:break-word"><span class=""><div></div><div>There is this sample code by Thorsten Seitz with a cached property which is quite simple and clear : <a href="https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170911/039684.html" target="_blank">https://lists.swift.org/<wbr>pipermail/swift-evolution/<wbr>Week-of-Mon-20170911/039684.<wbr>html</a></div><div><br></div></span><div>This is the sample code that had me enter the &quot;worried&quot; camp.&#39;</div></div></blockquote><div><br></div><div>I really like Thorsten&#39;s example, because it actually proves that requiring explicit derivation is NOT the correct approach here. (Let&#39;s set aside the fact that Optionals prevent synthesis because we don&#39;t have conditional conformances yet, and assume that we&#39;ve gotten that feature as well for the sake of argument.)</div><div><br></div><div>Let&#39;s look at two scenarios:</div><div><br></div><div>1) Imagine I have a value type with a number of simple Equatable properties. In a world where synthesis is explicit, I tell that value type to &quot;derive Equatable&quot;. Everything is fine. Later, I decide to add some cache property like in Thorsten&#39;s example, and that property just happens to also be Equatable. After doing so, the correct thing to do would be to remove the &quot;derive&quot; part and provide my custom implementation. But if I forget to do that, the synthesized operator still exists and applies to that type. If you&#39;re arguing that &quot;derive Equatable&quot; is better because its explicitness prevents errors, you must also accept that there are possibly just as many cases where that explicitness does *not* prevent errors.</div><div><br></div><div>2) Imagine I have a value type with 10 Equatable properties and one caching property that also happens to be Equatable. The solution being proposed here says that I&#39;m better off with explicit synthesis because if I conform that type to Equatable without &quot;derive&quot;, I get an error, and then I can provide my own custom implementation. But I have to provide that custom implementation *anyway* to ignore the caching property even if we don&#39;t make synthesis explicit. Making it explicit hasn&#39;t saved me any work—it&#39;s only given me a compiler error for a problem that I already knew I needed to resolve. If we tack on Hashable and Codable to that type, then I still have to write a significant amount of boilerplate for those custom operations. Furthermore, if synthesis is explicit, I have *more* work because I have to declare it explicitly even for types where the problem above does not occur.</div><div><br></div><div>So, making derivation explicit is simply a non-useful dodge that doesn&#39;t solve the underlying problem, which is this: Swift&#39;s type system currently does not distinguish between Equatable properties that *do* contribute to the &quot;value&quot; of their containing instance vs. Equatable properties that *do not* contribute to the &quot;value&quot; of their containing instance. It&#39;s the difference between behavior based on a type and additional business logic implemented on top of those types.</div><div><br></div><div>So, what I&#39;m trying to encourage people to see is this: saying &quot;there are some cases where synthesis is risky because it&#39;s incompatible with certain semantics, so let&#39;s make it explicit everywhere&quot; is trying to fix the wrong problem. What we should be looking at is <b>&quot;how do we give Swift the additional semantic information it needs to make the appropriate decision about what to synthesize?&quot;</b></div><div><br></div><div>That&#39;s where concepts like &quot;transient&quot; come in. If I have an Equatable/Hashable/Codable type with 10 properties and one cache property, I *still* want the synthesis for those first 10 properties. I don&#39;t want the presence of *one* property to force me to write all of that boilerplate myself. I just want to tell the compiler which properties to ignore.</div><div><br></div><div>Imagine you&#39;re a stranger reading the code to such a type for the first time. Which would be easier for you to quickly understand? The version with custom implementations of ==, hashValue, init(from:), and encode(to:) all covering 10 or more properties that you have to read through to figure out what&#39;s being ignored (and make sure that the author has done so correctly), or the version that conforms to those protocols, does not contain a custom implementation, and has each transient property clearly marked? The latter is more concise and &quot;transient&quot; carries semantic weight that gets buried in a handwritten implementation.</div><div><br></div><div>Here&#39;s a fun exercise—you can actually write something like &quot;transient&quot; without any additional language support today: <a href="https://gist.github.com/allevato/e1aab2b7b2ced72431c3cf4de71d306d" target="_blank">https://gist.github.com/<wbr>allevato/<wbr>e1aab2b7b2ced72431c3cf4de71d30<wbr>6d</a>. A big drawback to this Transient type is that it&#39;s not as easy to use as an Optional because of the additional sugar that Swift provides for the latter, but one could expand it with some helper properties and methods to sugar it up the best that the language will allow today.</div><div><br></div><div>I would wager that this concept, either as a wrapper type or as a built-in property attribute, would solve a significant majority of cases where synthesis is viewed to be &quot;risky&quot;. If we accept that premise, then we can back to our slice of pie and all we&#39;re left with in terms of &quot;risky&quot; types are &quot;types that contain properties that conform to a certain protocol but are not really transient but also shouldn&#39;t be included verbatim in synthesized operations&quot;. I&#39;m struggling to imagine a type that fits that description, so if they do exist, it&#39;s doubtful that they&#39;re a common enough problem to warrant introducing more complexity into the protocol conformance system. </div></div></div></blockquote></div></div></div></div></div></div>