[swift-evolution] [Review] SE-0091: Improving operator requirements in protocols

Brent Royal-Gordon brent at architechies.com
Wed May 25 04:21:03 CDT 2016

> Brent, I think it's even slightly more complicated than that. Think e.g. how two subclass instances of NSArray should compare equal even if they've got different types. (I really dislike class inheritance for these reasons, but below is my take on how we could better live with the issue in Swift.)

If you're referring to this:

>> 	guard let other = other as? Self else {
>> 		return super == other
>> 	}

I probably should have said `#Self`, meaning e.g. `NSArray` if you're implementing `NSArray.==`. What you really want to test for there is the *static* type of `self`, not the dynamic type.

If you're referring to the multiple dispatch thing, I actually think that will handle subclassing perfectly well. If you have a class hierarchy like this, with each class implementing its own `(Self, Self)` equality operation:


Then using `==` on `MyArray` and `MyOtherArray` should use `(NSArray, NSArray).==()`, which presumably would compare the length and elements to test for equality.

> For the very example of Equatable and Foundation classes, we would get the right behaviour for NSObject's `isEqual` by changing the definition of Equatable into:
>     protocol Equatable {
>         associatedtype EqualSelf = Self // the default is ok pretty much always
>         func == (lhs: Self, rhs: EqualSelf) -> Bool
>         func != (lhs: Self, rhs: EqualSelf) -> Bool
>     }
> This way, the compiler would always be looking for the `(Self, NSObject) -> Bool` shape of operation, which actually picks up statically the correct overload for `lhs.isEqual(rhs)`.

But you would need to do this for all operators. A protocol that requires `<` or `+` would need to de-privilege the right-hand side in exactly the same way.

Brent Royal-Gordon

More information about the swift-evolution mailing list