<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=""><div class="">A different way of layering could be allowing value types to be composed, where the outer type inherits the inner member’s properties and methods.</div><div class=""><br class=""></div><div class="">Let’s say you want only fields ‘contentID’ and ‘contentData' to participate in equality and hashing, but not ‘revisionID':</div><div class=""><br class=""></div><div class=""> struct ContentInfo : Equatable, Hashable { // Automatic implementations for == and hashValue are provided since members conform<br class=""> let contentID: NSUUID<br class=""> let contentData: NSData<br class=""> }</div><div class=""><br class=""></div><div class=""> struct RevisionInfo : Equatable, Hashable {</div><div class=""> let revisionID: NSUUID<br class=""> private let content: ContentInfo // Hidden from the outside world</div><div class=""> public compose content // Adds .contentID, .contentData, .hashValue properties to RevisionInfo that delegate to those of `content`<br class=""> }</div><div class=""><br class=""></div><div class=""><div class=""> func ==(lhs: RevisionInfo, rhs: RevisionInfo) -> Bool {</div></div><div class=""> return lhs.content == rhs.content</div><div class=""> }</div><div class=""><br class=""></div><br class=""><div><blockquote type="cite" class=""><div class="">On 28 May 2016, at 5:41 AM, plx via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><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 May 27, 2016, at 10:48 AM, Matthew Johnson <<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><blockquote type="cite" class="" 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;"><div class=""><br class="Apple-interchange-newline">On May 27, 2016, at 10:37 AM, plx via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class="">On May 26, 2016, at 1:00 PM, T.J. Usiyan via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">A `deriving` keyword, at the very least, is pretty explicitly *not* an all-or-nothing situation. If you want to define equality/hashability for your type manually, don't use `deriving`. This should leave the simplest cases to auto generation and anything more complex should be handled by the developer.</div></div></blockquote><div class=""><br class=""></div><div class="">It’s all-or-nothing in the sense you can’t use a naive `deriving` implementation to assist in any case where what you need is *almost* the trivial implementation, but not quite.</div><div class=""><br class=""></div><div class="">Consider a case like this:</div><div class=""><br class=""></div><div class=""> class QuxEvaluator {</div><div class=""> </div><div class=""> let foo: Foo // Equatable</div><div class=""> let bar: Bar // Equatable</div><div class=""> let baz: Baz // Equatable</div><div class=""><br class=""></div><div class=""> private var quxCache: [QuxIdentifier:Qux] // [Equatable:Equatable] = [:]</div><div class=""><br class=""></div><div class=""> // pure function of `foo`, `bar`, `baz`, and `identifier`</div><div class=""> // expensive, and uses `quxCache` for memoization </div><div class=""> func qux(for identifier: QuxIdentifier) -> Qux</div><div class=""><br class=""></div><div class=""> }</div><div class=""><br class=""></div><div class="">…if it weren’t for `quxCache` we could easily synthesize `==` for `QuxEvaluator`, but the trivial synthesis will yield invalid results due to `[QuxIdentifier:Qux]` also being `Equatable` (really: it *will* also be equatable once conditional conformances are in place).</div><div class=""><br class=""></div><div class="">So we’re back to e.g. writing this: </div><div class=""><br class=""></div><div class=""> extension QuxEvaluator : Equatable {</div><div class=""><br class=""></div><div class=""> }</div><div class=""><br class=""></div><div class=""> func ==(lhs: QuxEvaluator, rhs: QuxEvaluator) -> Bool {</div><div class=""> return (lhs === rhs) || (lhs.foo == rhs.foo && lhs.bar == rhs.bar && lhs.baz == rhs.baz)</div><div class=""> }</div><div class=""><br class=""></div><div class="">…just to omit a single field from the `==` consideration; this is another sense in which you can say deriving is an all-or-none; there’s just no way to invoke the synthesis mechanism other than for "all fields”.</div></div></div></div></blockquote><div class="" 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;"><br class=""></div><div class="" 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;">I don’t see why this must necessarily be the case. Annotations such as you describe below could be taken into account by `deriving`. `deriving` is just a way to invoke the synthesis mechanism.</div></div></blockquote><div class=""><br class=""></div><div class="">Different people are using it differently I think; I agree with you if it’s just the name of the invocation, but I think at least some people are using it as a shorthand for the “naive” implementation (all fields equatable => equatable).</div><div class=""><br class=""></div><div class="">That is, I meant "naive deriving” to refer to something like this (quoting Patrick):</div><div class=""><br class=""></div><div class=""><div class=""><blockquote type="cite" class="">It would fail if not all members were Equatable or Hashable. If it was automatic, you wouldn’t get any warning or sign at all. If you have to explicitly conform to the protocols, then your intention is clear, and if an automatic implementation cannot be made (because not all members were Equatable or Hashable), then you will get an error that you need to implement the protocol yourself like you do now (i.e. implement == and hashValue).</blockquote></div><div class=""><br class=""></div></div><div class="">…but I could’ve been clearer!</div><br class=""><blockquote type="cite" class=""><div class=""><br class="" 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;"><blockquote type="cite" class="" 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;"><div class=""><div 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="">On the one hand, it’s possible to imagine a finer-grained form of this synthesis that’d allow you to e.g. indicate a certain field should be omitted (and also perhaps specialize how fields are compared, customize the synthesized comparison ordering to put cheaper comparisons earlier, and an endless list of other possible requests…).</div></div></div></div></blockquote><div class="" 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;"><br class=""></div><div class="" 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;">If you don’t trust the compiler to optimize this well and therefore want control over order of comparisons you should probably just implement it manually. As you note below, this is a convenience feature that needs to strike a fine balance.</div></div></blockquote><div class=""><br class=""></div><div class="">I agree, but at the same time i think that scenarios like this:</div><div class=""><br class=""></div><div class=""> struct RevisionInfo {</div><div class=""> let contentID: NSUUID</div><div class=""> let revisionID: NSUUID</div><div class=""> let contentData: NSData</div><div class=""> }</div><div class=""><br class=""></div><div class="">…aren’t going to be all that uncommon in practice; I think a good “layered” implementation of the derivation/synthesis logic would suffice (e.g. we wouldn't *need* special-case handling for ordering, potentially…).</div><br class=""><blockquote type="cite" class=""><div class=""><div class="" 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;"><br class=""></div><div class="" 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;">IMO there are two issues involved:</div><div class="" 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;"><br class=""></div><div class="" 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;">1. How do we invoke the automatic synthesis.</div><div class="" 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;">2. How do we have some degree of control over the synthesis that happens.</div><div class="" 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;"><br class=""></div><div class="" 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;">`deriving` addresses issue 1 and says nothing about issue 2.</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="">Agreed here; 2 is the interesting question. If you look at my initial response in this thread I tried to suggest a “layered” approach:</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="">Layer A: have some way of directly invoking the synthesis mechanism itself (e.g. as a special-purpose macro-like construct); it should be powerful enough to make `==` easy to write, but have some flexibility (implemented or planned-for-future).</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="">Layer B: add a way to synthesize `==` (etc.) via the construct from Layer A.</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=""> </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="">That’s my 2c on this topic; given it’s a Swift 4 topic at the very earliest there’s a lot of time to figure it out.</div><span 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; float: none; display: inline !important;" class="">_______________________________________________</span><br 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 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; float: none; display: inline !important;" class="">swift-evolution mailing list</span><br 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=""><a href="mailto:swift-evolution@swift.org" 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="">swift-evolution@swift.org</a><br 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=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" 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="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></div></blockquote></div><br class=""></body></html>