3

I can create Sets in ES6:

let s = new Set([1, 2, 3]);
let q = new Set([3, 1, 2]);

but can't compare them by what they contain.

console.log(s == q); // --> false

No .equals(other) method is provided in the API, only .has(), delete(), etc. Naively, to me it seems like it would be easy to implement -- why wasn't it?

(I'm not looking for workarounds, like those provided in this answer. I'm just wondering why this decision was made, since there's certainly something about the circumstances surrounding it that I don't understand.)

Community
  • 1
  • 1
Eli Rose
  • 6,788
  • 8
  • 35
  • 55
  • Don´t really know, but you can literally add anything to a set, including objects. So guess they did not want to deal with that – juvian Feb 01 '16 at 17:45
  • @juvian: But they do this already with `.has()`, don't they? That works by reference equality. – Eli Rose Feb 01 '16 at 18:42
  • 1
    One would have to go back and review the deliberations of the standards committee. Perhaps it was considered. However, I imagine it was not. As @JimboJonny points out, other object types have no such equality API. The language designers are quite conservative when it comes to adding features, especially ones that can be easily implemented in userland. –  Feb 01 '16 at 18:48

1 Answers1

1

This is not new.

Equivalency of non-primitives (i.e. objects) compares whether they are literally the same actual object. This is not a new concept. Works the same for other non-primitive stuff in JS:

var a = [1,2,3];
var b = [1,2,3];
console.log(a == b); // -> false

var c = {foo:'bar'};
var d = {foo:'bar'};
console.log(c == d); // -> false

Why do primitives/objects compare differently?

Simple: because the concept of whether 2 primitives are the "same" is different from the concept of whether 2 objects are the "same".

You actually can make multiple references to the same object, therefore checking whether 2 references are "the same" takes on a meaning very different from primitives. They literally might be actual pointers to the same object:

var str1 = 'foo';
var str2 = str1;
str2 += ' bar';
console.log(str2); // -> "foo bar"
console.log(str1); // -> still just "foo"
// str1 is unchanged, primitives don't do pointers

var obj1 = {val:'foo'};
var obj2 = obj1;
obj2.val += ' bar';
console.log(obj2.val); // -> "foo bar"
console.log(obj1.val); // -> "foo bar"
// obj1 and obj2 are LITERALLY pointers to the same thing
// changing one changes the other

So it makes sense that with primitives (where one entire point of their existence is that the values are primitive enough that we can compare them even while they are not actually pointing to the same actual 1's and 0's internally) might act different from non-primitives (where 2 values may literally point to the same 1's and 0's internally) when we ask the question "are they equivalent"?


Not to mention the technical difficulties.

Primitives are called such for a reason: they are simple/primitive values. They are easy to compare because of that.

Objects are much more complex by design. They can even hold references to other objects...and even to themselves. Comparing them the way you imply should be done would be a possibly infinite iterative process rather than a simple operator action. Consider this:

var a = {foo:'bar'};
a.a = a;
console.log(a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.foo); // -> bar
// could go on forever that way

Making something like checking equivalency suddenly mean iterative processes that are possibly infinite would profoundly and negatively impact a language. It makes far more sense that they just check whether they are literally equal (i.e. point to the same exact object).

Jimbo Jonny
  • 3,549
  • 1
  • 19
  • 23
  • Hi, thanks for the answer! I suppose that, in my head, I'm comparing JS to Python, which provides an `__eq__` that is called by `a == b`. In Python, checking equivalency is an iterative process that is potentially infinite, as you say, when `a` contains a reference to itself. Hence I don't think "It makes far more sense to check whether they are literally equal" is self-evidently true. What do you think accounts for the difference in the languages? – Eli Rose Feb 01 '16 at 18:52
  • @EliRose - You're gonna have to explain better, because my experience with python is that it works the exact same in this regard. E.g. this code: http://pastie.org/10704573 would output `false` then `true` just like the equivalent JS code would. Granted, I'm not a python expert, but I know enough to compare vars and print the output and it seems to act just like JS in this regard when I do so. – Jimbo Jonny Feb 01 '16 at 19:27
  • 1
    Although all of this is good stuff, and might be and probably is part of the reason this equality check is not supported, but bottom line is that it's speculation about the thought processes of the language designers. –  Feb 01 '16 at 19:28
  • @JimboJonny: Yep, Python works the same in this regard, *except* if you define the special `__eq__` method on the class. Here's an example: https://repl.it/Bije/0. This allows e.g. `[1, 2, 3] == [1, 2, 3]` to be true in Python although it is false in Javascript. Java does the same thing with `equals()`. So one question I have is what design decision led to JS not providing an `__eq__` hook. – Eli Rose Feb 01 '16 at 19:50
  • @EliRose - That's just operator overloading where you are defining an algorithm to run on `==`. You could define it to return `"purple"` whenever you compare. That doesn't mean it's logical to ask why `==` in JS doesn't evaluate to `"purple"`. And within your overloading notice that you have to go down to the expected primitive values to make your comparisons work as expected. Introduce another non-primitive value without custom overloading in a place where you expected a primitive in your overload code and it fails yet again: https://repl.it/Bije/1 – Jimbo Jonny Feb 01 '16 at 20:08
  • @JimboJonny: You're right that it fails if you don't specify it. I'm not disputing that, by default, `==` works the same way in both languages. It does, and it should! But Python allows this type of overloading, and I'm just wondering what the obstacle is in JS. – Eli Rose Feb 01 '16 at 20:17
  • @EliRose - That's not really a question about comparing object equality though. Python doesn't treat object equality any differently...you're just overloading the operator to make it check some property values and return a custom result and YOU are treating that object equality differently...just like you could add a `Object.prototype.equals = function(obj){ ... };` method ...[continued] – Jimbo Jonny Feb 01 '16 at 20:23
  • @EliRose - ...to do any random thing in JS...including check some property values and return a custom result, and then call `oneObject.equals(anotherObject);` or make `function compare(obj1, obj2){ ... }` and call `compare(o1, o2);`. In both the only way it's gonna compare individual props is if you make an algorithm to do it...the only difference is the syntax you use to run it. – Jimbo Jonny Feb 01 '16 at 20:24
  • @EliRose - basically what I'm saying is, you say you don't want a workaround, you want to know why JS doesn't have the ability to compare differently like Python does...but in reality **the only reason python does is because you're using a workaround** by overloading the operator and making a custom algorithm to do it. That IS a workaround. – Jimbo Jonny Feb 01 '16 at 20:27