Closed grantneufeld closed 8 months ago
FYI your example code does not compile for me as I get the diagnostic:
🛑 Redundant conformance of 'BrokenEqualityAssertionTests.SubExperiment' to protocol 'Equatable'
XCTAssertEqual()
simply calls ==
(well, !=
, but that calls through to ==
for types conforming to Equatable
.)
This is a general constraint of protocol conformances on classes in Swift: the superclass is the type that conforms, and subclasses are not able to override the superclass' conformance when it involves a reference to Self
, because the override's type (Self
) won't match.
What's happening here is that the ==
operator implemented in the subclass is valid, in isolation, independent of Equatable
conformance, and when you explicitly write one == two
the compiler type-checks the expression and says "==(lhs: SubExperiment, rhs: SubExperiment)
is the best match among overloads of ==
".
On the other hand, when you call XCTAssertEqual()
, it is relying on Equatable
conformance and, as a generic implementation, cannot see the overload of ==
in the subclass. It can only see the overload of ==
that satisfies the parent class' Equatable
conformance, i.e. ==(lhs: SuperExperiment, rhs: SuperExperiment)
.
The solution depends on your real-world code: if these classes are actually subclasses of NSObject
, then override isEqual(_:)
instead of ==
. If these classes are not subclasses of NSObject
, then you can emulate what NSObject
does by adding an open
member to the base class and having ==
call it. However, be aware that when dealing with classes and inheritance, it can be difficult to ensure that the symmetric property of ==
is preserved if the base class is not aware of all possible subclasses.
Oh, well. Thanks for looking into it. In the end, I gave up on using inheritance and reworked the whole thing with protocols instead. 🤷
When comparing two instances of a subclass, if both the subclass and its parent class conform to
Equatable
with both having their own equality operator function (static func ==
), XCTAssertEqual and XCTAssertNotEqual will use the superclass’ function rather than the subclass function.Xcode: 15.2 macOS: 14.3.1
Sample test file showing the error: