[Review] SE-0185 - Synthesizing Equatable and Hashable conformance

If the only difference were whether the default implementation was generated by a macro or not, would you still think auto-derivation should be marked with a keyword?


With or without a macro the issue here is still that the synthesised behaviour is generated based upon assumptions about a concrete type, whereas current default implementations are only based upon the methods/properties that are defined by the protocol itself, i.e- if the protocol is well-defined, and you implement it accordingly, then all a default implementation should be doing is correctly using the protocol. The problem with the synthesised behaviour is that it must necessarily make assumptions about parts of the concrete type that are not defined by the protocol and may in fact have nothing to do with it at all (e.g- could be properties implementing an entirely different protocol).

Whether or not this is generated by a macro is not the issue. If we assume macros will eventually replace features like this one, then I would still want a clear standard on how to distinguish between opting in to synthesised behaviour such as this.

To be clear as well; I didn't specifically request a keyword. In fact I'm leaning more towards separate protocols personally; i.e- if you just want to adopt the requirements you would conform to Equatable, but if you want to use the synthesised behaviour you would instead conform to AutoEquatable (or some similar naming convention). The important distinction here being that simply conforming to Equatable will still give you all the usual errors for failed requirements, at which point you can either fulfil them, or switch to AutoEquatable instead if you prefer.

This kind of standard would make sense for any protocol that wants to add default implementations that are "invasive", i.e- delve deeper into the concrete type than simply what the protocol itself defines as possible, i.e- behaviours that by their very nature must make assumptions about the concrete type. This might be fine for a protocol that is clearly defined as having such behaviour from the start, but personally I'd rather see a standard set that has it split off into a more specific protocol, such that we still have "pure" protocols which remain primarily as a set of requirements.

In other words, Equatable would contain all the basic requirements and the "non invasive" default implementations, while AutoEquatable would extend it with the macros/special behaviour that provides the synthesised defaults, allowing a developer to opt-in to them explicitly.

I disagree that @transient is crucial for this feature to work—that feature only applies to the set of types that contain volatile data, that volatile data and all the other fields are all Equatable/Hashable, and the user wants to synthesize Eq/Hash for a subset of its fields. I certainly agree that such a set is non-empty, but I it's also small enough that it can be considered at a later date.

I disagree with your reasons for disagreeing :stuck_out_tongue:

The problem is that synthesising the behaviour for such types right now will introduce a bug, and one that will not be exposed to developers except at runtime, which is something that makes me very uncomfortable. To be clear, my point is that a transient feature is a requirement now specifically because the proposal seeks to use conforming to Equatable as sufficient as an opt-in; if a more explicit opt-in were required then this would not be an issue, i.e- if a developer conforms to AutoEquatable instead of Equatable, then we can assume that they should know what that means, and should not do it unless they know their type contains no transient values.

With that kind of absolutely explicit opt-in then, yes, a @transient attribute or whatever can be deferred to a future feature. But with opt-in via Equatable conformance the lack of such a feature is much more pronounced. Though like I say, my preference is very much towards a more explicit opt-in, rather than an attribute/keyword that developers may not realise they need to use with regular Equatable (remember, not everyone will know that Equatable is gaining this new behaviour).

I sympathize with these concerns, and a great deal of thought and discussion was done around the best way to surface this feature in the last couple of mailing list threads about this topic. But at the time this proposal and its implementation were written, the synthesis for Codable had already been implemented and this proposal adopts the same synthesis conditions that were used by Codable. Core team members expressed that the implementation for Eq/Hash should follow those existing practices as closely as possible; I agreed that consistency is important so that we don't have to document intricate nuances between the implementations of protocol synthesis.

Given that constraint, IMO it would be incorrect for this proposal to create an inconsistent set of synthesis conditions compared to Codable, and it is out of scope for this proposal to suggest changes to Codable. If you feel that synthesis should be made more explicit across Equatable, Hashable, and Codable, please do propose that!

The problem with using Codable as a precedent (other than the fact auto-correct keeps trying to change it Coddle) is that it's an entirely new feature; there is no existing, well understood protocol that developers are already using day-to-day. Since it's new it can simply describe all of its default behaviour and expect developers to learn that before using it, but how many developers do we really expect to re-learn Equatable every time a new version of Swift is released? It's also arguable that conforming to Codable is already more of an explicit opt-in to the synthesised behaviour.

Equatable however has existing, well understood behaviour; if you don't implement == you get an error. This proposal is going to change that without any interaction with the developers at all; this was not an issue with Codable, and therefore I don't think it's a sound precedent to follow.

If consistency with Codable is a requirement, then I would argue that changes to Codable should come before this feature, e.g- split off Codable's synthesised behaviour into AutoCodable, then implement Equatable/Hashable's as AutoEquatable/AutoHashable afterwards, but personally I don't think it matters; Codable was free to define its behaviour as being an intrinsic part of it from the start, but Equatable/Hashable already exist.


On 10 Aug 2017, at 23:29, Brent Royal-Gordon <brent@architechies.com> wrote:
On 10 Aug 2017, at 16:19, Tony Allevato <tony.allevato@gmail.com> wrote: