Home:ALL Converter>Why must we define both == and != in C#?

Why must we define both == and != in C#?

Ask Time:2011-08-03T02:37:13         Author:Stefan Dragnev

Json Formatter

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.

Author:Stefan Dragnev,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/6916884/why-must-we-define-both-and-in-c
Dan Abramov :

This is what comes to my mind first:\n\n\nWhat if testing inequality is much faster than testing equality? \nWhat if in some cases you want to return false both for == and != (i.e. if they can't be compared for some reason)\n",
2011-08-02T20:01:54
Greg Hendershott :

The key words in your question are \"why\" and \"must\".\n\nAs a result:\n\nAnswering it's this way because they designed it to be so, is true ... but not answering the \"why\" part of your question.\n\nAnswering that it might sometimes be helpful to override both of these independently, is true ... but not answering the \"must\" part of your question.\n\nI think the simple answer is that there isn't any convincing reason why C# requires you to override both.\n\nThe language should allow you to override only ==, and provide you a default implementation of != that is ! that. If you happen to want to override != as well, have at it.\n\nIt wasn't a good decision. Humans design languages, humans aren't perfect, C# isn't perfect. Shrug and Q.E.D.",
2011-08-02T21:31:40
GolezTrol :

Well, it's probably just a design choice, but as you say, x!= y doesn't have to be the same as !(x == y). By not adding a default implementation, you are certain that you cannot forget to implement a specific implementation. And if it's indeed as trivial as you say, you can just implement one using the other. I don't see how this is 'poor practise'.\n\nThere may be some other differences between C# and Lua too...",
2011-08-02T18:43:24
Andrew Russell :

Just to add to the excellent answers here:\n\nConsider what would happen in the debugger, when you try to step into a != operator and end up in an == operator instead! Talk about confusing!\n\nIt makes sense that CLR would allow you the freedom to leave out one or other of the operators - as it must work with many languages. But there are plenty of examples of C# not exposing CLR features (ref returns and locals, for example), and plenty of examples of implementing features not in the CLR itself (eg: using, lock, foreach, etc).",
2011-08-03T13:06:07
Josh :

Programming languages are syntactical rearrangements of exceptionally complex logical statement. With that in mind, can you define a case of equality without defining a case of non-equality? The answer is no. For an object a to be equal to object b, then the inverse of object a does not equal b must also be true. Another way to show this is \n\nif a == b then !(a != b)\n\nthis provides the definite ability for the language to determine the equality of objects. For instance, the comparison NULL != NULL can throw a wrench into the definition of a equality system that does not implement a non-equality statement. \n\nNow, in regards to the idea of != simply being replaceable definition as in\n\nif !(a==b) then a!=b\n\nI can't argue with that. However, it was most likely a decision by the C# language specification group that the programmer be forced to explicitly define the equality and and non-equality of an object together",
2011-08-02T19:31:09
Yuck :

Probably for if someone needs to implement three-valued logic (i.e. null). In cases like that - ANSI standard SQL, for instance - the operators can't simply be negated depending on the input.\n\nYou could have a case where:\n\nvar a = SomeObject();\n\n\nAnd a == true returns false and a == false also returns false.",
2011-08-02T18:44:41
Emoire :

In short, forced consistency.\n\n'==' and '!=' are always true opposites, no matter how you define them, defined as such by their verbal definition of \"equals\" and \"not equals.\" By only defining one of them, you open yourself up to an equality operator inconsistency where both '==' and '!=' can both be true or both be false for two given values. You must define both since when you elect to define one, you must also define the other appropriately so that it is blatantly clear what your definition of \"equality\" is. The other solution for the compiler is to only allow you to override '==' OR '!=' and leave the other as inherently negating the other. Obviously, that isn't the case with the C# compiler and I'm sure there's a valid reason for that that may be attributable strictly as a choice of simplicity. \n\nThe question you should be asking is \"why do I need to override the operators?\" That is a strong decision to make which requires strong reasoning. For objects, '==' and '!=' compare by reference. If you are to override them to NOT compare by reference, you are creating a general operator inconsistency that is not apparent to any other developer who would peruse that code. If you are attempting to ask the question \"is the state of these two instances equivalent?,\" then you should implement IEquatible, define Equals() and utilize that method call. \n\nLastly, IEquatable() does not define NotEquals() for the same reasoning: potential to open up equality operator inconsistencies. NotEquals() should ALWAYS return !Equals(). By opening up the definition of of NotEquals() to the class implementing Equals(), you are once again forcing the issue of consistency in determining equality.\n\nEdit: This is simply my reasoning.",
2011-08-03T16:39:59
Rag :

Other than that C# defers to C++ in many areas, the best explanation I can think of is that in some cases you might want to take a slightly different approach to proving \"not equality\" than to proving \"equality\". \n\nObviously with string comparison, for example, you can just test for equality and return out of the loop when you see nonmatching characters. However, it might not be so clean with more complicated problems. The bloom filter comes to mind; it's very easy to quickly tell if the element is not in the set, but difficult to tell if the element is in the set. While the same return technique could apply, the code might not be as pretty.",
2011-08-02T18:59:55
hatchet - done with SOverflow :

If you look at implementations of overloads of == and != in the .net source, they often don't implement != as !(left == right). They implement it fully (like ==) with negated logic. For example, DateTime implements == as\n\nreturn d1.InternalTicks == d2.InternalTicks;\n\n\nand != as\n\nreturn d1.InternalTicks != d2.InternalTicks;\n\n\nIf you (or the compiler if it did it implicitly) were to implement != as\n\nreturn !(d1==d2);\n\n\nthen you are making an assumption about the internal implementation of == and != in the things your class is referencing. Avoiding that assumption may be the philosophy behind their decision.",
2011-08-02T19:13:43
KeithS :

To answer your edit, regarding why you are forced to override both if you override one, it's all in the inheritance.\n\nIf you override ==, most likely to provide some sort of semantic or structural equality (for instance, DateTimes are equal if their InternalTicks properties are equal even through they may be different instances), then you are changing the default behavior of the operator from Object, which is the parent of all .NET objects. The == operator is, in C#, a method, whose base implementation Object.operator(==) performs a referential comparison. Object.operator(!=) is another, different method, which also performs a referential comparison. \n\nIn almost any other case of method overriding, it would be illogical to presume that overriding one method would also result in a behavioral change to an antonymic method. If you created a class with Increment() and Decrement() methods, and overrode Increment() in a child class, would you expect Decrement() to also be overridden with the opposite of your overridden behavior? The compiler can't be made smart enough to generate an inverse function for any implementation of an operator in all possible cases.\n\nHowever, operators, though implemented very similarly to methods, conceptually work in pairs; == and !=, < and >, and <= and >=. It would be illogical in this case from the standpoint of a consumer to think that != worked any differently than ==. So, the compiler can't be made to assume that a!=b == !(a==b) in all cases, but it's generally expected that == and != should operate in a similar fashion, so the compiler forces you to implement in pairs, however you actually end up doing that. If, for your class, a!=b == !(a==b), then simply implement the != operator using !(==), but if that rule does not hold in all cases for your object (for instance, if comparison with a particular value, equal or unequal, is not valid), then you have to be smarter than the IDE.\n\nThe REAL question that should be asked is why < and > and <= and >= are pairs for comparative operators that must be implemented concurrently, when in numeric terms !(a < b) == a >= b and !(a > b) == a <= b. You should be required to implement all four if you override one, and you should probably be required to override == (and !=) as well, because (a <= b) == (a == b) if a is semantically equal to b.",
2011-08-02T22:54:21
Chris Mullins :

If you overload == for your custom type, and not != then it will be handled by the != operator for object != object since everything is derived from object, and this would be much different than CustomType != CustomType. \n\nAlso the language creators probably wanted it this way to allow the most most flexibility for coders, and also so that they are not making assumptions about what you intend to do.",
2011-08-02T19:31:37
yy