Equality can be checked by value and by reference. Value equality is tested using the operators == and !=, while reference equality is tested with the operators === and !==.
To test value equality, the operators == and != are used. In the case of data types, the operation a == b will perform a test of field equivalence for every field of the data type. For arrays, the equivalence of each cell in the array is checked. Note that in both of these cases, the equality check does not follow any references; instead references are considered equal if they reference the exact same entity instance.
To help see how this works, consider the following example type:
data Example {
int a
int b
bool c
}
We can instantiate this data type multiple times like this:
Example e1 = new Example(12, 44, true)
Example e2 = new Example(12, 44, true)
Example e3 = new Example(12, 43, true)
Each of the above instances is in a distinct memory area, such that a reference equality check of e1 === e2 would return false. The value equality check:
e1 == e2
...will return true, since each field in the two data instances has the same value. The comparison:
e2 == e3
...will return false, since the second field of the instances has a different value.
Now consider the following example, which has fields of reference type:
data ExampleB {
int a
int b
char name[]
}
Again we instantiate the data type three times:
ExampleB e1 = new ExampleB(12, 44, "Alex")
ExampleB e2 = new ExampleB(12, 44, e1.name)
ExampleB e3 = new ExampleB(12, 44, "Alex")
When we perform this test:
e1 == e2
...the value of each field is compared, and the reference-type field name is checked using a reference equality check ===. This is because value-based equality checks on data instances do not recursively follow reference type fields of those instances, instead using a reference check on such fields. The equality check e1 == e2 returns true, because e2 references the same char[] instance as e1. By comparison, the test:
e1 == e3
...returns false, because the name field references a different char[] instance to that of e1. Note that, if you wished to write your own fully recursive value equality checker, you could do this using Dana's reflective operators.
For objects, the value equality operation a == b uses the object's equality function and is the same as (a == null && b == null) || a.equals(b).
To test reference equality, the operators === and !== are used. These operations check if two variables refer to exactly the same instance of a data type, array, or object.