The C# compiler requires that whenever a custom type defines operator ==
, it must also define !=
(see here).
Why?
I'm curious to know why the designers thought it necessary and why can't the compiler default to a reasonable implementation for either of the operators when only the other is present. For example, Lua lets you define only the equality operator and you get the other for free. C# could do the same by asking you to define either == or both == and != and then automatically compile the missing != operator as !(left == right)
.
I understand that there are weird corner cases where some entities may neither be equal nor unequal, (like IEEE-754 NaN's), but those seem like the exception, not the rule. So this doesn't explain why the C# compiler designers made the exception the rule.
I've seen cases of poor workmanship where the equality operator is defined, then the inequality operator is a copy-paste with each and every comparison reversed and every && switched to a || (you get the point... basically !(a==b) expanded through De Morgan's rules). That's poor practice that the compiler could eliminate by design, as is the case with Lua.
Note: The same holds for operators < > <= >=. I can't imagine cases where you'll need to define these in unnatural ways. Lua lets you define only < and <= and defines >= and > naturally through the formers' negation. Why doesn't C# do the same (at least 'by default')?
EDIT
Apparently there are valid reasons to allow the programmer to implement checks for equality and inequality however they like. Some of the answers point to cases where that may be nice.
The kernel of my question, however, is why this is forcibly required in C# when usually it's not logically necessary?
It is also in striking contrast to design choices for .NET interfaces like Object.Equals
, IEquatable.Equals
IEqualityComparer.Equals
where the lack of a NotEquals
counterpart shows that the framework considers !Equals()
objects as unequal and that's that. Furthermore, classes like Dictionary
and methods like .Contains()
depend exclusively on the aforementioned interfaces and do not use the operators directly even if they are defined. In fact, when ReSharper generates equality members, it defines both ==
and !=
in terms of Equals()
and even then only if the user chooses to generate operators at all. The equality operators aren't needed by the framework to understand object equality.
Basically, the .NET framework doesn't care about these operators, it only cares about a few Equals
methods. The decision to require both == and != operators to be defined in tandem by the user is related purely to the language design and not object semantics as far as .NET is concerned.