-
-
Save andymatuschak/a40c4c699c0abdd704ce 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 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.