Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is == overridden in System.Double but not in System.Int32 and what are the ramifications of that?

In C# Why does Double override == but Int32 does not, and what is the effect?

I look at the msdn library.

I see this link about double which doesn't say much here (though I understand double is a shorthand for the Double object).. It doesn't show methods for example..

but this link on System.Double does mention what I'm looking for here

It shows the Equality operator taking doubles, so overloaded.

Image For Double in MSDN, then after Methods (before listing Fields), it shows Operators, and it shows equality operator is overridden

enter image description here

and I can click Equality under "Operators" and it says

public static bool operator ==(
    double left,
    double right
)

Whereas when I look at System.Int32 Image For Int32 in MSDN is below

enter image description here

See in that image, (the page for System.Int32) it looks like == is not overridden.

Why, and what are the ramifications of this?

like image 896
barlop Avatar asked Apr 21 '14 19:04

barlop


People also ask

Why should we override equals method in C#?

For a value type, you should always override Equals, because tests for equality that rely on reflection offer poor performance. You can also override the default implementation of Equals for reference types to test for value equality instead of reference equality and to define the precise meaning of value equality.

How to override. Equals method in c#?

Because Complex is a value type, it cannot be derived from. Therefore, the override to Equals(Object) method need not call GetType to determine the precise run-time type of each object, but can instead use the is operator in C# or the TypeOf operator in Visual Basic to check the type of the obj parameter.

Should override equals C#?

With value types, you should always override the == operator. Like the Equals method, the default implementation of the == operator uses reflection and is slow. Use the same logic as the Equals method, and you'll get much better performance when you're doing equality comparisons on value types.

Can we use equals method for integer C#?

Equals(Int32) This method is used to return a value indicating whether the current instance is equal to a specified Int32 value or not. Syntax: public bool Equals (int obj);


2 Answers

One possible reason is because of the Double.NaN.

For the == operator: MSDN says: If two Double.NaN values are tested for equality by using the equality operator(==), the result is false; two Double.NaN values are not considered equal. If they are tested for equality by calling the Equals method, the result is true. When you want to determine whether the value of a Double is not a number (NaN), an alternative is to call the IsNaN method.

So the == operator and the Equals methods of Double have different behavior regards to Double.NaN, I think this why == is override for double. As for int, there's no such special case.

The code to demo the differences:

using System;

public class Example
{
   public static void Main()
   {
      Console.WriteLine("NaN == NaN: {0}", Double.NaN == Double.NaN); 
      Console.WriteLine("NaN != NaN: {0}", Double.NaN != Double.NaN); 
      Console.WriteLine("NaN.Equals(NaN): {0}", Double.NaN.Equals(Double.NaN)); 
      Console.WriteLine("! NaN.Equals(NaN): {0}", ! Double.NaN.Equals(Double.NaN)); 
      Console.WriteLine("IsNaN: {0}", Double.IsNaN(Double.NaN));

      Console.WriteLine("\nNaN > NaN: {0}", Double.NaN > Double.NaN); 
      Console.WriteLine("NaN >= NaN: {0}", Double.NaN >= Double.NaN); 
      Console.WriteLine("NaN < NaN: {0}", Double.NaN < Double.NaN);
      Console.WriteLine("NaN < 100.0: {0}", Double.NaN < 100.0); 
      Console.WriteLine("NaN <= 100.0: {0}", Double.NaN <= 100.0); 
      Console.WriteLine("NaN >= 100.0: {0}", Double.NaN > 100.0);
      Console.WriteLine("NaN.CompareTo(NaN): {0}", Double.NaN.CompareTo(Double.NaN)); 
      Console.WriteLine("NaN.CompareTo(100.0): {0}", Double.NaN.CompareTo(100.0)); 
      Console.WriteLine("(100.0).CompareTo(Double.NaN): {0}", (100.0).CompareTo(Double.NaN)); 
   }
}
// The example displays the following output: 
//       NaN == NaN: False 
//       NaN != NaN: True 
//       NaN.Equals(NaN): True 
//       ! NaN.Equals(NaN): False 
//       IsNaN: True 
//        
//       NaN > NaN: False 
//       NaN >= NaN: False 
//       NaN < NaN: False 
//       NaN < 100.0: False 
//       NaN <= 100.0: False 
//       NaN >= 100.0: False 
//       NaN.CompareTo(NaN): 0 
//       NaN.CompareTo(100.0): -1 
//       (100.0).CompareTo(Double.NaN): 1

The code is also from MSDN

like image 60
Matt Avatar answered Oct 08 '22 06:10

Matt


Int32 seems to be very special in terms of .NET. The functionality that is missing from the source code is more than likely baked into core of the system.

You cannot compare structs/value-types with ==, >, etc. without declaring those operators inside the struct. Because Int32 is missing these I came to the conclusion above.

Doing a simple test and dumping the IL, they are doing the exact same comparison and no CompareTo or Equals is getting called (which I thought actually happened. I learned something!).

public void TestInts()
{
    var x = 1;
    var y = 2;
    var equals = x == y;
}

.method public hidebysig 
    instance void TestInts () cil managed 
{
    // Method begins at RVA 0x2094
    // Code size 11 (0xb)
    .maxstack 2
    .locals init (
        [0] int32 x,
        [1] int32 y,
        [2] bool equals
    )

    IL_0000: nop
    IL_0001: ldc.i4.1
    IL_0002: stloc.0
    IL_0003: ldc.i4.2
    IL_0004: stloc.1
    IL_0005: ldloc.0
    IL_0006: ldloc.1
    IL_0007: ceq
    IL_0009: stloc.2
    IL_000a: ret
}

public void TestDoubles()
{
    var x = 1.7d;
    var y = 1.5d;
    var equals = x == y;
}
.method public hidebysig 
    instance void TestDoubles () cil managed 
{
    // Method begins at RVA 0x20ac
    // Code size 27 (0x1b)
    .maxstack 2
    .locals init (
        [0] float64 x,
        [1] float64 y,
        [2] bool equals
    )

    IL_0000: nop
    IL_0001: ldc.r8 1.7
    IL_000a: stloc.0
    IL_000b: ldc.r8 1.5
    IL_0014: stloc.1
    IL_0015: ldloc.0
    IL_0016: ldloc.1
    IL_0017: ceq
    IL_0019: stloc.2
    IL_001a: ret
}

The above IL just has the standard ceq opcode called for both cases. By .NET standards, Int32 should have the comparison operators declared in the source code, but it does not.

EDIT: It appears as though all whole-number value-types are like this. Single, Double, Decimal all have the operators specified in the source code. Int16, Int32, Int64, Byte, do not.

like image 29
TyCobb Avatar answered Oct 08 '22 04:10

TyCobb