// 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 Value: HeteroEquatable {} | |
protocol Smashable { | |
func valueBySmashingOtherValue(value: Value) -> Value | |
} | |
extension Int: Value { | |
func isEqualTo(a: HeteroEquatable) -> Bool { | |
if let a = a as? Int { | |
return self == a | |
} else { | |
return false | |
} | |
} | |
} | |
struct Test { | |
func valueBySmashingOtherValue(value: Value) -> Value { | |
return 0 // This is free to return a different adopter of Value | |
} | |
} | |
let result = Test().valueBySmashingOtherValue(3) | |
println(result == 3) // can still == |
But that doesn't work with Brent's example: Bar() is not convertible to U
.
Which makes sense, since U is defined by the caller of the function and not the function itself. So returning Bar here isn't valid.
(accidentally deleted comment /o)
Oops, no, it's not fixed yet…
No, you can't do it currently AFAIK. Not without getting rid of the Self requirement of Equatable.
Okay. No. I don't think it's fixable in Swift currently.
Per @jckarter, Value
can't be both Equatable
and used as a dynamic type because Equatable
requires a Self
constraint, but the result of valueBySmashingOtherValue
would be type-erased, so you couldn't actually use it as an equatable…
You could get around this by making Value
heterogeneously equatable.
(updated to a version with Value
heterogeneously equatable)
Yeah, sorry, fixed.