Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jakebromberg/313cd471147c740437ad9e8d65f68c8c to your computer and use it in GitHub Desktop.
Save jakebromberg/313cd471147c740437ad9e8d65f68c8c to your computer and use it in GitHub Desktop.
// One note before we start: if the inhabitants of Value are a closed set,
// then making Value an enum is going to be a clearer model than using a
// protocol like this. I'm assuming you need to be able to retroactively add
// new members of Value.
// Can't use Equatable directly because of its Self requirement.
protocol HeteroEquatable {
func isEqualTo(_ value: HeteroEquatable) -> Bool
}
func ==(lhs: HeteroEquatable, rhs: HeteroEquatable) -> Bool {
return lhs.isEqualTo(rhs)
}
protocol Smashable {
func smash(with value: HeteroEquatable) -> HeteroEquatable
}
extension Int: HeteroEquatable { }
extension HeteroEquatable where Self: Equatable {
func isEqualTo(_ value: HeteroEquatable) -> Bool {
guard let value = value as? Self else {
return false
}
return self == value
}
}
struct Test: Smashable {
func smash(with value: HeteroEquatable) -> HeteroEquatable {
return 3 // This is free to return a different adopter of Value
}
}
let result = Test().smash(with: 3)
print(result == 3) // can still ==
@jakebromberg
Copy link
Author

Why is the indirection of the Value protocol necessary?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment