Is the JavaScript operator === provably transitive?
Asked Answered
G

3

11

JavaScript's quirky weakly-typed == operator can easily be shown to be non-transitive as follows:

var a = "16";
var b = 16;
var c = "0x10";
alert(a == b && b == c && a != c); // alerts true

I wonder if there are any similar tricks one can play with roundoff error, Infinity, or NaN that could should show === to be non-transitive, or if it can be proved to indeed be transitive.

Goiter answered 1/10, 2011 at 20:11 Comment(8)
Are you asking about JavaScript as defined by any particular ECMAScript version, or JavaScript as implemented in any particular browser?Jaye
@Ray == isn't transitive because of type coercion. === doesn't coerce...Sponge
@Jaye I was thinking of ECMAScript 5 but any version of JavaScript will do.Goiter
@Šime Vidas I know === does not coerce but I'm not sure that that constitutes a proof. It very well might....Goiter
@Ray I don't have the time right now to write an elaborate answer, but I've gone through all the cases of the "Strict Equality Comparison Algorithm", and I'm certain that === is transitive.Sponge
@Ray this a great one!i just noticed as well that a == c if c = 0x10 and not c = '0x10'. this is quite interesting!Rockling
Cheating: jsfiddle.net/JFVcG/1.Hoskinson
useful in alf.nu/ReturnTrueEncratia
P
3

The === operator in Javascript seems to be as transitive as it can get.

NaN is reliably different from NaN:

>>> 0/0 === 0/0
false
>>> 0/0 !== 0/0
true

Infinity is reliably equal to Infinity:

>>> 1/0 === 1/0
true
>>> 1/0 !== 1/0
false

Objects (hashes) are always different:

>>> var a = {}, b = {};
>>> a === b
false
>>> a !== b
true

And since the === operator does not perform any type coercion, no value conversion can occur, so the equality / inequality semantics of primitive types will remain consistent (i.e. won't contradict one another), interpreter bugs notwithstanding.

Paez answered 1/10, 2011 at 20:24 Comment(4)
+1 Ah, okay, this can be extended to a more formal full proof by cases on the 6 types of JavaScript: undefined, null, number, boolean, string, and object. Every value of every type is === ONLY to itself (with the exception of NaN which does not "hurt") with no overlaps even with object.Goiter
@Ray, to be fair, the null type is still a work in progress to this day (e.g. typeof null returns object in my Firefox 6). The sixth type is actually function, which is distinct from object because it has to implement call().Submerged
@RayToal Check this answerEncyclical
@FrédéricHamidi Thanks. I am aware of the workings of typeof and the fact that typeof null is "object" and that the operator returns "function" but the workings of this operator is orthogonal to the fact that ECMAScript 5 has six types, regardless of what this operator says. See Chapter 8 of the ECMAScript 5 Spec; it is perfectly clear about the six ECMAScript language types.Goiter
T
2

If you look at the spec (http://bclary.com/2004/11/07/#a-11.9.6) you will see that no type coercion is being made. Also, everything else is pretty straightforward, so maybe only implementation bugs will make it non-transitive.

Teahan answered 1/10, 2011 at 20:19 Comment(1)
Thanks for the link to the spec. A positive proof will have to be made by cases on this definition. I'll try working it out over the next day or so and will accept if it pans out.Goiter
E
1

Assuming you have variable a,b, and c you can't be 100% certain as shown here. If someone is doing something as hackish as above in production, well then you probably have bigger problems ;)

var a = 1;
var b = 1;
Object.defineProperty(window,"c",{get:function(){return b++;}});

alert(a === b && b === c && a !== c); // alerts true
Encyclical answered 1/10, 2011 at 20:56 Comment(3)
Nice one, found that as well but it's rather cheating :) After all, it's not the === that's failing, but rather the fact that the variables are changing. I guess it's implied that a, b and c stay to the same value in the definition of transitivity.Hoskinson
@Hoskinson In the context of what the coder sees a,b, and c are not changing, and therefore it is not transitive a === b && b === c && a !== c but hey I guess that is stretching it :DEncyclical
@Encyclical yes very clever, but I would say yes it's a stretch. I was asking about transitivity in terms of values, not variables. The difference matters, but it's a very cool illustration nevertheless!Goiter

© 2022 - 2024 — McMap. All rights reserved.