Objecten vergelijken.

Een veel voorkomend en veel besproken onderwerp is het vergelijken van objecten. Dit blijft een interessant onderwerp en het kan zeker geen kwaad om er eens in te duiken. De functionaliteit werkt op het eerste gezicht verwarrend en verschilt over talen/frameworks heen. Java en .NET bieden ons een tweetal opties: Equals() en de == operator. In de meeste projecten worden deze door elkaar gebruikt en totaal willekeurig. Is dit handig? Is het niet beter om één te kiezen voor alles? Zijn er ook verschillen tussen beide?

In deze post zal ik voornamelijk ingaan op het verschil tussen de twee methodes in het .Net framework. Hiervoor gebruik ik een op internet veel voorkomende snippet. In deze C# snippet heb ik voor het gemak de uitkomst van de vergelijkingen achter de regel code gezet in commentaar.

Console.WriteLine("Code Snippet #1");

String a = new String(new char[] { 'h', 'e', 'l', 'l', 'o' });
String b = new String(new char[] { 'h', 'e', 'l', 'l', 'o' });

Console.WriteLine(a == b); // 1: true
Console.WriteLine(a.Equals(b)); // 2: true

Object c = a;
Object d = b;

Console.WriteLine(c == d); // 3: false
Console.WriteLine(c.Equals(d)); // 4: true

Wat mij opvalt hier is het resultaat van vergelijking 1. Waarom is dit true terwijl er twee verschillende objecten gemaakt worden? Dat er een verschil is tussen Equals en == blijkt uit het verschil in de resultaten bij 3 en 4. Hierover is genoeg te vinden op MSDN en andere websites. Een korte samenvatting hierover en hoe dit werkt:

Overriding en overloading

De Equals methode is als virtual methode gedefinieerd in System.Object en kan dus overridden worden door elke class. Equals maakt dus gebruik van polymorphisme. De == operator is één van de operatoren die overloaded kan worden. Hierdoor kan men aan de == operator een andere implementatie toekennen binnen een klasse. Mocht de operator niet zijn overloaded, dan pakt de compiler de standaard implementatie voor de == operator.

Manieren van vergelijking

Na gekeken te hebben naar de technische verschillen, kijken we naar de inhoudelijke verschillen van vergelijking. Er zijn twee manieren van vergelijking:

Identity comparison; houdt in dat bij een vergelijking gecheckt wordt of beide referenties naar het zelfde object wijzen.

Value comparison; houdt in dat bij een vergelijking gecheckt zal worden of de achterliggende waarde gelijk is.

De manier van vergelijking wordt niet alleen bepaald door de methode (Equals of ==), maar ook of de objecten die vergeleken worden van het type: value type of reference type zijn. Bij het vergelijken van value types zullen Equals en == standaard value comparison gebruiken. Bij referentie types verschillen Equals en == wel in werking. De implementatie van Equals in System.Object class gebruikt identity comparison. Dus Equals gebruikt standaard identity comparison (en alleen maar value comparison voor classes waarin deze method overridden is). De == operator maakt standaard gebruik van de identity comparison. De enige uitzondering hierop is dat == voor Strings de value comparison gebruikt (dit verklaart ook de uitkomst van vergelijking 1 in de snippet). De keuze hiervoor is wel begrijpelijk aangezien Strings immutable zijn. Immers, de enige String-input voor de identity comparison die true oplevert is namelijk de String vergeleken met zichzelf. In Java is hier overigens trouwens niet voor gekozen en levert vergelijking 1 false als resultaat.

Maar welke methode moet men nou gebruiken? Dit is dus afhankelijk van waarop men wil vergelijken. Als men referentie types wil vergelijken op waarde dan is het logisch Equals te gebruiken, wil men vergelijken op referenties dan kan men het beste == gebruiken. In .Net moet er dan wel op gelet worden dat de == operator zich voor Strings iets anders gedraagt.

Hoe zou dit in andere talen zijn..?