Python 'is' vs JavaScript === - javascript

The Python use of 'is' seems to be similar to JavaScript '===' but not quite.
Here they talk about exact instances:
http://www.learnpython.org/en/Conditions
here (for JS) they talk about "equal AND the same type."
http://www.w3schools.com/js/js_comparisons.asp
SO can you have two different instances of (say) a string of "Bob" and have them not return true when compared using 'is'? Or is it infact the same as ===?
I am guessing this is related to strict vs non-strict typed languages. . . .

Python Part
SO can you have two different instances of (say) a string of "Bob" and
have them not return true when compared using 'is'? Or is it infact
the same as ===?
a = "Bob"
b = "{}".format("Bob")
print a, b
print a is b, a == b
Output
Bob Bob
False True
Note: In most of the Python implementations, compile time Strings are interned.
Another example,
print 3 is 2+1
print 300 is 200+100
Output
True
False
This is because, small ints (-5 to 256) in Python are cached internally. So, whenever they are used in the programs, the cached integers are used. So, is will return True for them. But if we choose bigger numbers, like in the second example, (300 is 200+100) it is not True, because they are NOT cached.
Conclusion:
is will return True only when the objects being compared are the same object, which means they point to the same location in memory. (It solely depends on the python implementation to cache/intern objects. In that case, is will return True)
Rule of thumb:
NEVER use is operator to check if two objects have the same value.
JavaScript Part
Other part of your question is about === operator. Lets see how that operator works.
Quoting from ECMA 5.1 Specs, The Strict Equality Comparison Algorithm is defined like this
If Type(x) is different from Type(y), return false.
If Type(x) is Undefined, return true.
If Type(x) is Null, return true.
If Type(x) is Number, then
If x is NaN, return false.
If y is NaN, return false.
If x is the same Number value as y, return true.
If x is +0 and y is −0, return true.
If x is −0 and y is +0, return true.
Return false.
If Type(x) is String, then return true if x and y are exactly the
same sequence of characters (same length and same characters in
corresponding positions); otherwise, return false.
If Type(x) is Boolean, return true if x and y are both true or both
false; otherwise, return false.
Return true if x and y refer to the same object. Otherwise, return
false.
Final Conclusion
We can NOT compare Python's is operator and JavaScript's === operator, because Python's is operator does only the last item in the Strict Equality Comparison Algorithm.
7. Return true if x and y refer to the same object. Otherwise, return false.

Completely different.
>>> a = 'foo'
>>> b = 'bar'
>>> a + b is 'foobar'
False
>>> 1000 + 1 is 1001
False

>>> a = "Hello, World!!!"
>>> b = "Hello, World!!!"
>>> a is b
False
However note that:
>>> a = "Bob"
>>> b = "Bob"
>>> a is b
True
In this case it condition was True because the compiler is free to intern string literals, and thus reuse the same object, and it does do that with small strings. However there is no guarantee as to when this happens of if this happens at all and the behaviour changes between versions and implementations.
A realiable False output should be:
>>> a = 'Hello, World!!!!'[:-1]
>>> b = 'Hello, World!!!!'[:-1]
>>> a is b
False
Or anything that actually computes the strings.

Python's is keyword compares references (and so is about identity) while === does a minimal amount of coercion (and is therefore concerned with equality, at least in the case of primitives) so they are different.
As I understand it, things that are concerned with identity are concerned with uniqueness from the runtime's point of view (do these two variables point to the same address in memory) while equality is concerned with the uniqueness of the contents of the variables (are these two variables equivalent, regardless of where they are placed in memory relative to each other).

Related

Does the `===` operator in Javascript have separate definitions for primitives vs non-primitives?

With the === operator in Javascript, if it operators on primitives, it returns false if either the values are different or the types are different. If it's operating on non-primitives, it returns false if the two operands don't point to the same object.
This seems like the === has separate definitions when applied to primitives and non-primitives. Like "if operands are primitives, do this, else do this". Is there a broader definition of === that encompasses its treatment of both primitives and non-primitives? Like "whether primitives or non-primitive, do this"?
Yes, to some extent - there's a bit of a process here.
7.2.15 IsStrictlyEqual ( x, y )
If Type(x) is different from Type(y), return false.
If x is a Number, then Return Number::equal(x, y).
Return SameValueNonNumber(x, y).
and
7.2.12 SameValueNonNumber ( x, y )
Assert: Type(x) is the same as Type(y).
If x is a BigInt, then
a. Return BigInt::equal(x, y).
If x is undefined, return true.
If x is null, return true.
If x is a String, then
a. If x and y are exactly the same sequence of code units (same length and same code units at corresponding indices), return true; otherwise, return false.
If x is a Boolean, then
a. If x and y are both true or both false, return true; otherwise, return false.
If x is a Symbol, then
a. If x and y are both the same Symbol value, return true; otherwise, return false.
If x and y are the same Object value, return true. Otherwise, return false.
The only real answer here is the spec, where we see === defined:
EqualityExpression : EqualityExpression === RelationalExpression
1. Let lref be ? Evaluation of EqualityExpression.
2. Let lval be ? GetValue(lref).
3. Let rref be ? Evaluation of RelationalExpression.
4. Let rval be ? GetValue(rref).
5. Return IsStrictlyEqual(rval, lval).
So we're comparing "whatever the GetValue spec function says we should be comparing", paired with "and we have to use the strict equality test for that", so we're not so much comparing "two primitive values, or two references". There's a few more steps involved, which have zero relevance to "actually using JS" in most circumstances, so for practical purposes they simply don't matter...but when you have fundamental questions, the spec is the fundaments =)

Comparison Behaviour of JavaScript Objects

We suppose that we have 3 variables : a,b and c
var a = new Boolean(true);
var b = true;
var c = new Boolean(true);
console.log("First comparison : ", a == b);
// true
console.log("Second comparison : ", b == c);
// true
console.log("Contradiction : ", a == c);
// false
I already know that the keyword 'new' creates a new object.
The type of this object, is simply object.
Mathematically, how can we explain this contradiction ?
In the first two examples, since the comparison involves a primitive value of b, a and c end up being coerced to primitives. In the last case, on the other hand, you are comparing two distinct objects, and therefore no coercion takes place.
To be precise, the double-equal comparison with a boolean uses this rule from the spec (taking the case of b == c):
If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
So this means that ToNumber(b) is compared with c. ToNumber(b) is 1. So we are comparing 1 with c. Next, the following rule is applied:
If Type(x) is either String or Number and Type(y) is Object,
return the result of the comparison x == ToPrimitive(y).
So this means we compare 1 with ToPrimitive(c) which is ToPrimitive(Boolean(true)). ToPrimitive invokes valueOf, which yields 1. So we compare 1 to 1. QED.
In the case of your third example, the following portion of the spec applies:
If Type(x) is the same as Type(y), then...Return true if x and y refer to the same object. Otherwise, return false.
To answer your question:
Mathematically, how can we explain this contradiction ?
It's not a matter of mathematics. It's a matter of the definition of comparisons in the JS spec.
Mathematically, how can we explain this contradiction?
If you think this is a contradiction is probably because you assumed that == defines an equivalence relation.
But it doesn't:
It doesn't satisfy reflexivity, e.g. NaN != NaN.
It doesn't satisfy transitivity, as you noticed.
It satisfies symmetry, though, but that alone is not enough.
I don't think this kind of behaviour can be explained from a mathematical standpoint.
What you are doing on the variables a and c is commonly referred as "boxing": taking a Javascript primitive value (undefined, null, String, Number, Boolean, Symbol in ES6) and calling it with the newoperator.
The result of:
var a = new Boolean(true);
is a Javascript Objectwrapping a Boolean primitive value.
The same invocation pattern implicitly happens when you use a primitive value as the context (this) in some of the language built-in facilities such as Function.prototype.call and Function.prototype.apply
Even replacing ==with === would yield the same results, and that's because of how the Objects comparison work in JS.

JavaScript array comparison strange behaviour [duplicate]

This question already has answers here:
Why is `[] == false` is true but just `[]` evaluates to true? [duplicate]
(4 answers)
Closed 8 years ago.
I'm trying to figure out why JavaScript has this strange behaviour in comparing the same array:
var array = [0];
console.log(array == array); //true
console.log(array == !array); //true?
The first one is easily done, they are referencing the same object, but the second is a really tricky one, and I'm working on understanding the process.
Please note that I'm aware that this is abstract equality comparison and not strict equality comparison, and I know their differences (I know that using === would lead to false result, but I'm trying to figure out the behaviour with ==).
P.s.: this one was taken from wtfjs.com, and I didn't find out the explanation, so I tried to give it myself and thought it could be "useful".
The first equality is simple, it's a comparison between the same object (same reference), so it returns true.
The second one is a bit tricky, so I'll try to explain better below.
TL;DR
For those who are a bit lazy, here is a simple explanation without quoting the spec every step:
[0] == ![0] => we evaluate ![0] first, which yields false(because [0] is a truthy value).
[0] == false => [0] is evaluated to [0].toString() which is "0".
"0" == false => "0" is converted to the number 0; the same is for false, so we obtain:
0 == 0 which is finally true.
Complete explanation
As for the first equality, for the sake of completeness, I quote here the interested part of the spec.
1.f Return true if x and y refer to the same object. Otherwise, return false.
So this returns true, as expected. Now the tricky part:
First of all, we have to evaluate the UnaryExpression on the right:
Let expr be the result of evaluating UnaryExpression.
Let oldValue be ToBoolean (GetValue(expr) ).
If oldValue is true, return false.
Return true.
But ToBoolean uses this algorithm, and GetValue should return either an Object or a non-empty String, so the result of the evaluation is true. Returning to our UnaryExpression, we have !true, so the result of the final evaluation is false.
So we're back at our original comparison, now we are comparing an Object against a Boolean.
7.If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
ToNumber(false) is 0, so now we are comparing Object and Number.
Back to the specs:
9.If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.
Calling ToPrimitive on our array should return its [[DefaultValue]], which should be, according to this kangax's answer, the result of calling toString on the array itself, so we obtain "0".
So, back to our comparison, it has became an equality between a String and a Number.
5.If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
Calling ToNumber on our string "0" yields 0, again we are finally at a simple comparison: 0 == 0.
Final spec step:
1.c.iii If x is the same Number value as y, return true.
And here the result explained.
The algorithm for the == operator evaluates the expressions from left to right, so given:
var array = [0];
and evaluating:
array == !array;
then first the left hand expression is evaluated and an array is returned. Then the right hand expression is evaluated: ToBoolean is applied to array and, since it's an object, it returns true and the ! operator reverses that to false.
Then the abstract equailty comparison algorithm is used. Again, the left hand side is evaluated first. Since array is an Object and not a Boolean, String or Number, step 7 is used and the right hand side is converted to a Number and the comparison becomes:
array == 0;
The algorithm is run again and gets to step 9, where array is converted to a primitive (string in this case) and the comparison becomes:
'0' == 0;
The algorithm is run again and gets to step 5 where the left hand side is converted to a Number and the comparison becomes:
0 == 0;
The algorithm is run again and this time the expressions have the same Type (Number) so step 1.iii.c is used to return true.
Please note that through all of this, the left hand side is always evaluated first, though sometimes that results in the right hand side being modified and not the left (e.g. at step 7 of the algorithm).

[] is not identical to [] [duplicate]

This question already has answers here:
How to compare arrays in JavaScript?
(55 answers)
Closed 9 years ago.
I was asked to write a function sortByFoo in Javascript that would react correctly to this test :
// Does not crash on an empty array
console.log(sortByFoo([]) === []);
But I've tried something :
[] === [];
>> false
Just so I can be sure, such a test would always fail, no matter the sortByFoo function, wouldn't it ?
But I'd like to have an explanation on why this happens. Why [] isn't identical/equal to [] ?
Please forgive my approximate english, it is not my native language :p
If you look at the specification for javascript/ecmascript, particularly section 11.9.6, you will see how comparisons with === are performed.
The Strict Equality Comparison Algorithm
The comparison x === y, where x and y are values, produces true or false. Such a comparison is performed as follows:
If Type(x) is different from Type(y), return false.
If Type(x) is Undefined, return true.
If Type(x) is Null, return true.
If Type(x) is Number, then
If x is NaN, return false.
If y is NaN, return false.
If x is the same Number value as y, return true.
If x is +0 and y is −0, return true.
If x is −0 and y is +0, return true.
Return false.
If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions); otherwise, return false.
If Type(x) is Boolean, return true if x and y are both true or both false; otherwise, return false.
Return true if x and y refer to the same object. Otherwise, return false.
Since your arrays go all the way down to the seventh step they will have to be the same object, not just two identical objects. The same goes for the regular equality operator (==).
Because every time you write [] you are calling array's constructor.
[] is the same as new Array(), and in Javascript new objects compared with equals method are different. See the reference, it is the same as new Object() when using {}.
When you do [] === [] you're comparing references and not values (or deep comparison by values).
Take a look at this solution for javascript array comparison: Comparing two arrays in Javascript
Yes, you are correct that two array literals are never equal. That's because they are references to two separate instances of arrays.
The code to describe the test should be written:
var arr = [];
var result = sortByFoo(arr);
console.log(result === arr && result.length == 0);
Checking that the reference returned by the function is the same that was sent in, and that the array is still empty, ensures that the function returned the same array unchanged.

When is a JavaScript String not a string? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why does (“foo” === new String(“foo”)) evaluate to false in JavaScript?
Over here I caught the advice that it's best to use non type-coercive string comparison, but in Chrome, I discovered something kind of odd:
var t1 = String("Hello world!");
var t2 = new String("Hello world!");
var b1 = (t1==t2); // true
var b2 = (t1===t2); // false
Is this standard behavior? If so, what are the respective types of t1 and t2? Thanks.
If you don't use the "new" keyword with String, you get a primitive string.
If you use "new" keyword, you get a string object instead of primitive.
When you use == it will try to convert to a comparable type, so it can be equal.
If you use ===, it won't convert, so an object can not equal a primitive.
Here is the explanation
typeof String("Hello world!");
"string"
And:
typeof new String("Hello world!");
"object"
when you use === it is paying attention to the type so it returns false
String, called as a function, converts its argument to a string. String, called as a constructor, creates an object whose prototype is the String function. (Check James's Answer for the relevant ECMAScript specification section.)
This is indeed confusing.
The two equality operators actually do very different things. From the ECMA-262, v 5.1 document, === does:
If Type(x) is different from Type(y), return false.
If Type(x) is Undefined, return true.
If Type(x) is Null, return true.
If Type(x) is Number, then
a. If x is NaN, return false.
b. If y is NaN, return false.
c. If x is the same Number value as y, return true.
d. If x is +0 and y is -0, return true.
e. If x is -0 and y is +0, return true.
f. Return false.
If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions); otherwise, return false.
If Type(x) is Boolean, return true if x and y are both true or both false; otherwise, return false.
Return true if x and y refer to the same object. Otherwise, return false.
Whereas == does:
If Type(x) is the same as Type(y), then
a. If Type(x) is Undefined, return true.
b. If Type(x) is Null, return true.
c. If Type(x) is Number, then
i. If x is NaN, return false.
ii. If y is NaN, return false.
iii. If x is the same Number value as y, return true.
iv. If x is +0 and y is -0, return true.
v. If x is -0 and y is +0, return true.
vi. Return false.
d. If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions). Otherwise, return false.
e. If Type(x) is Boolean, return true if x and y are both true or both false. Otherwise, return false.
f. Return true if x and y refer to the same object. Otherwise, return false.
If x is null and y is undefined, return true.
If x is undefined and y is null, return true.
If Type(x) is Number and Type(y) is String, return the result of the comparison
x == ToNumber(y).
If Type(x) is String and Type(y) is Number, return the result of the comparison
ToNumber(x) == y.
If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
If Type(x) is either String or Number and Type(y) is Object, return the result of the comparison x == ToPrimitive(y).
If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.
Return false.
Note that in the spec, the Type of a primitive string object is String, whereas the type of any object (including the String object) is Object.
With === the relevant line is #1: the Type of the objects are different, so false is returned.
With == the relevant line is #8: x is a String ("Hello world!") and y is an Object (The String object containing the string "Hello world!"). Thus the comparison x == ToPrimitive(y) is made. ToPrimitive ends up calling the valueOf method of the object, or if that method doesn't exist, the toString method. In this case, a String object's valueOf method returns the primitive string the object contains. Thus the equality operation is done again, this time between two primitive strings which contain the same text, which returns true thanks to #1.d.
JavaScript is a bit messy under the hood...
EDIT: Notice that if two objects are compared, no conversions apply, but rather, rule #1.f applies. Thus, thanks to the spec, I was able to correctly predict the output of the following code:
> new String("hi") == new String("hi")
false
EDIT: Just thought I'd add that these distinctions are even further blurred by more implicit type conversion. For example, the following works:
> ("hi").toString()
"hi"
but that's not because "hi" is an object (like in Python):
> typeof "hi"
"string"
But rather, because the . operator does a conversion from the primitive string type to the string Object type (creating a new string object) whose toString method is then called.
This behaviour is detailed in the ECMAScript 5 specification, 15.5.1 and 15.5.2:
When String is called as a function rather than as a constructor, it performs a type conversion.
...
Returns a String value (not a String object) computed by ToString(value). If value is not supplied, the empty String "" is returned.
So String("some string") creates a string value.
When String is called as part of a new expression, it is a constructor: it initialises the newly created object.
So new String("some string") creates an instance of the String object.
And to actually answer your questions:
Is this standard behavior?
Yes, for the reasons detailed above.
If so, what are the respective types of t1 and t2
You can check this with the typeof operator:
console.log(typeof t1); //string
console.log(typeof t2); //object
This is happening because the == operator only checks if the values are the same, whereas === checks both the value and type. new String("Hello world!") is not actually being given the type string, it is an object, while String("Hello world!") is actually a string.
The first example String("Hello world!)" creates a primitive string while the second example new String("Hello world!") creates an String object.

Categories

Resources