Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why integer zero does not equal long zero?

Tags:

A strange piece of code I've just discovered in C# (should also be true for other CLI languages using .NET's structs).

using System;

public class Program
{
    public static void Main(string[] args)
    {
    int a;
    long b;

    a = 0;
    b = 0;

    Console.WriteLine(a.Equals(b)); // False
    Console.WriteLine(a.Equals(0L)); // False
    Console.WriteLine(a.Equals((long)0)); // False
    Console.WriteLine(a.Equals(0)); // True
    Console.WriteLine(a.Equals(a)); // True
    Console.WriteLine(a == b); // True
    Console.WriteLine(a == 0L); // True

    Console.WriteLine();

    Console.WriteLine(b.Equals(a)); // True
    Console.WriteLine(b.Equals(0)); // True
    Console.WriteLine(b.Equals((int)0)); // True
    Console.WriteLine(b.Equals(b)); // True
    Console.WriteLine(b == a); // True
    Console.WriteLine(b == 0); // True
    }
}

Two interesting points here (assuming that a is int and b is long):

  1. a != b, but b == a;
  2. (a.Equals(b)) != (a == b)

Is there any reason why comparison was implemented this way?

Note: .NET 4 was used if it makes any difference.

like image 993
paulius_l Avatar asked Feb 23 '12 19:02

paulius_l


People also ask

Is 0 An integer in C#?

Introduction to the C# integersIntegers are whole numbers for example -1, 0, 1, 2, 3. C# uses the integral numeric types to represent integer numbers.

Can an integer start with 0 in Java?

Zeros are ignored at the start of an int . If you need the zeros to be displayed, store the number as a String instead. If you need to use it for calculations later, you can convert it to an int using Integer.


1 Answers

In general, Equals() methods are not supposed to return true for objects of different types.

a.Equals(b) calls int.Equals(object), which can only return true for boxed Int32s:

public override bool Equals(Object obj) { 
    if (!(obj is Int32)) {
        return false;
    }
    return m_value == ((Int32)obj).m_value; 
}  

b.Equals(a) calls long.Equals(long) after implicitly converting the int to a long.
It therefore compares the two longs directly, returning true.

To understand more clearly, look at the IL generated by this simpler example (which prints True False True):

int a = 0;
long b = 0L;

Console.WriteLine(a == b);
Console.WriteLine(a.Equals(b));
Console.WriteLine(b.Equals(a));

IL_0000:  ldc.i4.0    
IL_0001:  stloc.0     
IL_0002:  ldc.i4.0    
IL_0003:  conv.i8     
IL_0004:  stloc.1     

IL_0005:  ldloc.0     //Load a
IL_0006:  conv.i8     //Cast to long
IL_0007:  ldloc.1     //Load b
IL_0008:  ceq         //Native long equality check
IL_000A:  call        System.Console.WriteLine    //True

IL_000F:  ldloca.s    00            //Load the address of a to call a method on it
IL_0011:  ldloc.1                   //Load b
IL_0012:  box         System.Int64  //Box b to an Int64 Reference
IL_0017:  call        System.Int32.Equals
IL_001C:  call        System.Console.WriteLine    //False

IL_0021:  ldloca.s    01  //Load the address of b to call a method on it
IL_0023:  ldloc.0         //Load a
IL_0024:  conv.i8         //Convert a to Int64
IL_0025:  call        System.Int64.Equals
IL_002A:  call        System.Console.WriteLine    //True
like image 183
SLaks Avatar answered Oct 10 '22 03:10

SLaks