An "~=" operator already exists — it's the "pattern matching" operator:
It's used implicitly by the "switch" statement, to match its argument with cases. (Incidentally, this was a terrible design choice, because you can explicitly override the operator function for specific types, e.g. Int, which changes the meaning of every switch statement on a value of that type. It is trivially easy to create code where, apparently, 1 is equal to 2.)
The other problem with your suggestion, I think, is that you'll find the concept of equivalence won't stay neatly partitioned into a third choice, once you start expanding your range of custome types. Either you won't know how to define equivalence for all contexts, or you'll need multiple equivalence operators.
From this nay-saying perspective, you might do better to reserve XCTAssertEqual for situations where "==" is the correct comparison operator, and assert true/false on an explicit expression in other cases.
Thank you, Quincey. I had spaced on realizing that ~= was already defined. Should I go that route, I'd pick a unique operator. Good to know though about the ability to override that which would lead into issues.
You make a good point about equivalence in general. I think I'd be OK though as for now at least, I'd only implement an equivalence protocol on "leaf" types.
Recently, I've come across more situations where my implementation of Equatable ultimately needs to be split. For example, in unit testing, you want to make sure == operates on all properties in a struct or class (so that XCTAssertEqual can be used). But in production code, you may want == to only take certain properties into account.
I’m somewhat concerned by your problem statement. The
Equatableprotocol has very strict semantic requirements (see the discussion of “substitutability” in the docs) and it seems like your requirements are incompatible with those semantics.
Share and Enjoy
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"
Not to worry, Quinn; all my implementations of Equatable honor what is mentioned in that doc. I've been looking for a good solution to offer another function/operator to aid in situations where two items can be deemed "equivalent".
A simplified example of what I have is a model object that drives user settings. Equatable is used to determine if the user changed anything (i.e. do I need to perform a save operation?). "Equivalence" comes in though when I need to load resources based on those settings, yet the resources only depend upon a subset of the properties on the model object. I was planning on using "equivalence" to see if I can continue to used the currently-loaded resources or not.
Going back to Quincey's post above, it may be that a general solution would open a can of worms. I could always just implement well-named APIs on particular objects. So in the above example, have a 'func shouldReloadResources() -> Bool' that would compare only those specific properties to make its decision.