Loose Equality violates TransitivityPosted:
"0" == 0; // true
0 == ; // true
"0" == ; // false
Despite this, the above is not a bug. It conforms exactly to ECMAScript: IsLooselyEqual.
# Equivalence Relations
An Equivalence Relation is the mathematically formal term for what we intuitively understand as "equals". In order for a relation to be a valid
Equivalence Relation, it must satisfy the following three properties:
a == a.
- Symmetry: "If
a == bthen
b == a".
- Transitivity: "If
a == band
b == c, then
a == c.
By the way,
NaN == NaN; // false violates reflexivity. But there are reasons for that decision, which I will not get into in this post. If you are especially interested, I recommend: Wikipedia | Comparison with NaN
# The Easy Fix
The easiest way to alter loose equality (
==) to fix transitivity would be to treat all cross-type comparisons as false. This is exactly what the strict equality (
But that's boring. Let's entertain the question: are there ways we can preserve at least cross-type equalities, while also preserving transitivity?
# The Pitfalls
As soon as we allow even one equality across types we create a cross-type equivalence class.
Equivalence Class is the set of all elements which are equivalent to one another.
Once you have a cross-type equivalence class, you have to be very careful when considering new members of that class. It is not sufficient to check our intuition against just one member of the equivalence class, since equivalence with any member, implies equivalence to all members (via transitivity).
The above implies two statements:
- Distinct values of the same type must never be members of the same equivalence class.
- A maximal equivalence class has exactly one value from each type.
# A Silly Proposal
Given the boolean type has only two values, there can exist only two distinct equivalence classes including booleans. We can use this as the basis for a set of maximal equivalence classes.
false equivalence class:
true equivalence class:
false class includes seven values, exactly one value from each primitive type.
true class has five values. The only missing types are
null, which cannot be included without merging the two equivalence classes. I really don't like the use of
'true' as the canonically true string, but this is what we get for pushing an idea to its limit.
In reality prohibiting cross-type equality is a perfectly sensible decision and very easy to reason about. It's no wonder that
=== is greatly preferred to