FWIW, the problems with class inheritance and Equatable can be fixed by changing the definition of Equatable into using an associatedtype for the RHS:
protocol Equatable { typealias EqualSelf = Self func == (lhs: Self, rhs: EqualSelf) -> Bool func != (lhs: Self, rhs: EqualSelf) -> Bool } func != <T : Equatable>(lhs: T, rhs: T.EqualSelf) -> Bool { return !(lhs == rhs) } This way, a generic function of type Subclass will expect a comparison of type `(Subclass, Subclass.EqualSelf) -> Bool`, i.e. `(Subclass, Base) -> Bool`, so it'll do the right comparison. I'm not proposing this change because I haven't found but contrived use for it. But if there's demand (and a real use case) for e.g. making an existential of Equatable (say, a struct AnyEquatable), then this could be the fix. Value types will obviously keep working just like before, since T and T.EqualSelf are synonymous for them. — Pyry >> We do have some problems today, such as above where using `==` on a `(Base, >> Subclass as Base)` pair ends up calling `==(Base, Base)` because we lack >> multiple dispatch. What surprised me though was that the `eq` call between >> two `Subclass` instances passed to the trampoline operator ended up calling >> `Base.eq`. I would have expected `Subclass.eq` to be called there since the >> generic argument `T` was bound to `Subclass`. Today, a non-generic >> `==(Subclass, Subclass)` operator *does* do the right thing. > > The reason why the trampoline calls the ==(Base,Base) overload in > Subclass is because it is a part of the override chain for the base > class method that introduces the conformance. > > The reason why the non-generic ==(Subclass,Subclass) operator does the > right thing is because it is a better match for overload resolution of > == at the callsite. But if you have a (Subclass as Base, Subclass as > Base) pair, even today it will call ==(Base,Base). _______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution