The boolean methods = and ==
Last updated at 2:09 pm UTC on 16 January 2006
What is the difference between the boolean methods #= and #==?
In any programming language it is important to distinquish between the value of an object, and the object itself. This is the difference between identity and equivalence. You might say it is the difference between who it is and what it is. For example who I am is "Bob", what I am is "a doctor".
Additionally it is necessary to distinquish between names or references to objects, and the objects themselves, so that "Bob Smith" may be referred to as "Bob Smith", "Bob", or "Mr. Smith". These are three references to the same person.
In Squeak we may have two objects:
| objA objB |
we may assign different values to these objects:
objA := 1
objB := 2
In this case:
- objA = 2 is false because the value of objA is 1 not 2.
- objB = 1 is false because the value of objB is 2 not 1.
- objA = objB is false because these objects are assigned different values.
- objA == objB is false because these are different objects.
= answers true if they are the same object OR they are equivalent (same value of the instance variables), the definition of equivalent being one that can vary from class to class.
== answers true if the receiver and argument are the same object. This is a test for identity.
Now if we assign one object to the other as in:
objA := objB
In this case:
- objA = 2 is true because the value of objA is now 2.
- objB = 1 is still false because the value of objB has not changed.
- objA = objB is true because these objects are assigned the same value (in fact they are references to the same object).
- objA == objB is true because these are the same object referenced by different names.
| a b |
a _ 'hello, world'.
b _ a.
a == b. "<==== true"
a = b. "<==== true"
b _ a copy.
a == b. "<==== false"
a = b. "<==== true"
The above answers your vice-versa case. The case of #== being true and #= being false _could_ happen if you defined a class where #= returned false when presented with the same object. Why you would want to do that, however, I can't imagine. So the short answer is
== false and = true happens a lot.
== true and = false probably never happens in real life.
Implementation in the image
If you look at:
| thisObject otherObject |
otherObject _ self popStack.
thisObject _ self popStack.
self pushBool: thisObject = otherObject
This is invoked from the only one implementor of #== in the Squeak image.
"Primitive. Answer whether the receiver and the argument are the same
object (have the same object pointer). Do not redefine the
message == in any other class! Essential. No Lookup. Do not override in any subclass.
See Object documentation whatIsAPrimitive."
The "C" code produced for the VM just checks to see if the addressof this object is = to the address of that object. If they are then of course they are the same object.
Now to answer your questions about #== true but #= false. Well you would need a broken #= to have that case. However the reverse of course can be true
- = is true, but of course #== can be false.
Now #= is implemented 55 times in the image and can be quite complex
self class == aCT class ifFalse:[^false].
^rAdd = aCT rAdd and:[rMul = aCT rMul and:[
gAdd = aCT gAdd and:[gMul = aCT gMul and:[
bAdd = aCT bAdd and:[bMul = aCT bMul and:[
aAdd = aCT aAdd and:[aMul = aCT aMul]]]]]]]
If you have a bug where side effects of a message sent could alter an object, then sure you could have #== is true but #= is false because the object gets changed while checking it's state, but it's really a bug. I guess also having a high priority process alter the object well testing #= could also raise issues.
John M McIntosh
== is implemented only once in the image. = is implemented in various classes. Don't forget to implement = in your own classes if you want to test for equality and can't rely on the method of the superclass. Otherwise you might get unexpected results.
And don't forget the hash
"Since various classes (particularly Sets and Dictionaries) rely on the property that equal objects have equal hashes, you should override hash whenever you override =. It must be true that (a = b) implies (a hash = b hash). The contrapositive and the converse will not generally hold. " From: Squeak Language and Classes Reference