[swift-evolution] [Draft] Automatically deriving Equatable and Hashable for certain value types

plx plxswift at icloud.com
Thu May 26 08:54:56 CDT 2016


I really want synthesized equality (etc.), but having seen the previous discussions on this and related topics I am not sure that directly-deriving the `==` function is the right approach. 

The main reason I say this is that although this works great for the easy case — all fields equatable, do the obvious thing! — sooner or later people will want to customize it, which would ideally allow someone to say “do the obvious thing for a,b,c but let me handle d and e”, e.g. still get synthesis for the easy parts…but an approach that directly-synthesizes `==` for a type seems like it’ll be difficult to expand to support such customization.

Suppose instead that we had a “magic function” `T#memberwiseEqual(_:_:)` we could invoke like so:
 
  // the details are *very* bikesheddable here:
  func ==(lhs: Foo, rhs: Foo) -> Bool {
    return Foo#memberwiseEqual(lhs,rhs) // `#` b/c of "compiler magic”
    // ^ compiler error iff any of `Foo`’s members aren’t Equatable
  }

…which’d expand to the expected “lhs.a == rhs.a && lhs.b == rhs.b && …”. 

For trivial equatable synthesis this isn’t as nice as a full automatic derivation, but it seems like an *approach* that’d be much-better positioned for future expansion and enhancement, e.g.:

  extension Foo: Equatable {

   // mock syntax; probably too ambiguous for actual use but i think the idea is clear:
   private static func boringComponentsEqual(lhs: Foo, _ rhs: Foo) -> Bool {
      return Foo(boring,boring2,boringIII)#memberwiseEqual(lhs,rhs)
   }

  }

  func ==(lhs: Foo, rhs: Foo) -> Bool {
    return Foo.boringComponentsEqual(lhs,rhs) && // non-trivial equality logic here
  }

…as opposed to trying to retrofit various “customizations" onto a system that directly synthesizes `==` (without exposing any “internals", so to speak).

You can easily imagine a similar `#casewiseEqual` for enums (it seems likely to be trickier, but not impossible), and again a #memberwiseHash for hashing, and so on.

I think you can summarize the above as “all-in-one derivation is appealing, but I think pragmatically and looking-ahead it’s a better move to expose the 'synthesis mechanism’ itself (leaving it the user to do the 'final assembly’)”.

> On May 25, 2016, at 1:28 PM, Tony Allevato via swift-evolution <swift-evolution at swift.org> wrote:
> 
> I was inspired to put together a draft proposal based on an older discussion in the Universal Equality, Hashability, and Comparability thread <http://thread.gmane.org/gmane.comp.lang.swift.evolution/8919/ <http://thread.gmane.org/gmane.comp.lang.swift.evolution/8919/>> that recently got necromanced (thanks Mark Sands!).
> 
> I'm guessing that this would be a significant enough change that it's not possible for the Swift 3 timeline, but it's something that would benefit enough people that I want to make sure the discussion stays alive. If there are enough good feelings about it, I'll move it from my gist into an actual proposal PR.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160526/07607d4a/attachment.html>


More information about the swift-evolution mailing list