rulururu

post Don’t compare objects mindless

February 18th, 2008

Filed under: .NET, Java — Kai @ 11:27 pm

When comparing objects in .Net I sometimes have to think about what way is the right one for my current case.

Imagine we got two objects called a and b that hold some data. There are several ways to compare them to each other - but it fact it’s not as confusing as I first thought.

Basically we can compare two different things of an object:

  • Identity (reference equality): Two objects are identical if they actually are the same object in memory. If the point to the same reference in memory they are equal.
  • Equivalence (value equality): Two objects are equivalent if the value or values they contain are the same.
int a = 3; 
int b = 3;

In most cases you’d regard them as equal ’cause their values are the same. Compared by identitiy they’re not equal.
This is the first you’d always keep in mind.

if(a.Equals(b))
{ 
Console.WriteLine("a equals b...");
}

Equals() is a virtual method on System.Object. It’s intended to test for identity or equivalence as appropriate. If you have an own type definition you’d like to be compareable you can override it in your class. Althougth it’s not necessary because there’s a default override of .Equals() in the base class. System.ValueType which will work for any structs you set up. Before overwriting it you’d consider that it uses reflection, which is slow, and involves a certain amount of boxing.

Value types get refleced over their internal fields to see if they are all equal.
For reference types, the situation is different. In general I’d expect Equals() for reference types to do an identity comparison but certain reference types aren’t lightweight enough to work as value types, but nevertheless have value semantics. That means most reference types are compared by reference but some like System.String are compared by value.

if(object.Equals(a, b))
{ 
Console.WriteLine("a equals b...");
}


object.Equals(object, object)
is a static method on the object class. This method was designed to reduce effort for programmers to check if a is null before calling a.Equals(b).
Generally it’s about the same as above mentioned a.Equals(b) but it also returns true if both objects are null ’cause they point to the same reference.

if(object.ReferenceEquals(a, b))
{ 
Console.WriteLine("a has same reference as b...");
}

object.ReferenceEquals(object, object) compares the addresses on the memory where the objects are.
Normally whether value types occupy the we don’t care about the memory addresses of them when comparing. It isn’t relevant for anything we’d want to normally use them for.

The difficulty comes from the fact that ReferenceEquals expects two System.Objects as parameters. This means that our value types will get boxed onto the heap as they are passed in to this routine. Normally, because of the way the boxing process works, they will get boxed separately to different memory addresses on the heap.

String a = "test", b="test";
if(a == b)
{ 
Console.WriteLine("a is equal to b...");
}

== is propably the most used operator for equality testing.
For value types within the .NET Framework, == is implemented as you would expect, and will test for equivalence (value equality).

If you use the == operator with reference types without thinking, bad things can happen. For example if you compare data structures which are not the same but contain the same value they’ll be compared as objects which means the comparison is done for reference and the result will be false even though the values are the same.

If you’d like to compare e.g. as System.String by reference you can do that as well by casting them to object.

String a = "test", b="test";
if ((object) a == (object) b)
{
Console.WriteLine("a and b point have same reference");
}

a is b checks the type of the the objects it is given. It’s not the comparison you might expect by the name of the operator.

int a = 3, b=4;
if(a is b)
{ 
Console.WriteLine("a and b are both integer");
}

In Java the meaning of those methods is about the same but when using the == operator you’d be careful because it does always a reference comparison - that’s why most people when programming Java for the first time don’t get the expected results. When comparing Strings in Java you’d always use equals().

static String s1 = "test";
static String s2 = new String ("test");
public static void main (String [] args)
{
  System.out.println ((s1 == s2) ? "same reference" : "not same reference");
  System.out.println ((s1.equals (s2)) ? "same value" : "not same value");
}

C# makes comparing strings easy even for a novice programmer and without sacrificing flexibility. The compiler is smart enough to realize that the == operator, when used with Strings, compares values rather than references. The option to compare references, of course, is still open to the programmer.

Always make sure that you know what you want to compare before using one of those methods/opertors without thinking.

No Comments »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a comment

ruldrurd
Powered by WordPress, Content and Design by Kai Bellmann
Entries (RSS) and Comments (RSS)