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

Brent Royal-Gordon brent at architechies.com
Thu Aug 10 17:29:28 CDT 2017


> On Aug 10, 2017, at 3:40 AM, Haravikk via swift-evolution <swift-evolution at swift.org> wrote:
> 
> This is not the same as a default protocol implementation

Actually, I could easily imagine that a future version of Swift with macro support might do this with a default protocol implementation:

	extension Equatable {
		#generated static func == (lhs: Self, rhs: Self) -> Bool {
			switch self {
			case let self as Struct:
				let propertyPairs = properties.map { property in
					guard let property = property as? Property<Generated.Equatable> else {
						throw SynthesisError.invalidType(property, expected: Generated.Equatable.self)
					}
					return DependentExpressionPair<Generated.Equatable, SameType>(
						original: Expression { lhs.#property },
						dependent: Expression { rhs.#property }
					)
				}
				return FunctionBlock { return #equated(propertyPairs) }
				
			case let self as Enum:
				guard !all.isEmpty else {
					throw SynthesisError.invalid(self, message: "is an empty enum")
				}
				
				let cases: SwitchBody<(Generated.Self, Generated.Self)> = all.map { aCase in
					let valueCaptures = aCase.associatedValues.map { value in
						guard let value = value as? AssociatedValue<Generated.Equatable> else {
							throw SynthesisError.invalidType(value, expected: Generated.Equatable.self)
						}
						return DependentExpressionPair<Generated.Equatable, SameType>(
							original: Variable(type: value.type),
							dependent: Variable(type: value.type)
						)
					}
					
					return SwitchBody {
						case let (
							#aCase.pattern(capturingInto: valueCaptures.map(\.original)),
							#aCase.pattern(capturingInto: valueCaptures.map(\.dependent))
						):
							return #equated(valueCaptures)
					}
				}.joined()
				
				return FunctionBlock { switch (lhs, rhs) { #cases } }
				
			default:
				throw SynthesisError.invalid(self, message: "is not a struct or enum")
			}
		}
	}
	
	private #func equated(_ exprPairs: [DependentExpressionPair<Generated.Equatable, SameType>]) -> Expression<Generated.Bool> {
		return exprPairs.map { pair in
			Expression { #pair.original == #pair.dependent }
		}
		.reduce(Expression { true }) { earlier, this in
			Expression { #earlier && #this }
		}
	} 

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?

-- 
Brent Royal-Gordon
Architechies



More information about the swift-evolution mailing list