I'm a Python developer, making my first steps in JavaScript.
I started using Map and Set. They seem to have the same API as dict
and set
in Python, so I assumed they're a hashtable and I can count on O(1) lookup time.
But then, out of curiosity, I tried to see what would happen if I were to do this in Chrome's console:
new Set([new Set([1, 2, 3])])
What happens is this:
Set(1) {Set(3)}
JavaScript happily creates the set. How can this be? In Python you would have gotten an error since you can't put a mutable item in a set or a dict. Why does JavaScript allow it?
Consider the following JS code:
> m1 = new Map([['a', 1]])
Map { 'a' => 1 }
> m2 = new Map()
Map {}
> m2.set(m1, 3)
Map { Map { 'a' => 1 } => 3 }
> m2.get(m1)
3
But note, it is hashing based on identity, i.e. ===
, so...
> m2.get(new Map([['a',1]]))
undefined
So really, how useful is this map?
Note, this isn't different than Python's default behavior. The default status of user-defined type is being hashable:
>>> class Foo: pass
...
>>> f0 = Foo()
>>> s = {f0}
>>> Foo() in s
False
>>> f0 in s
True
In Python, by default, object.__eq__
will compare based on identity, so the above is fine. However, if you override __eq__
, by default, __hash__
is set to None
and trying to use a hashing-based container will fail:
>>> class Bar:
... def __init__(self, value):
... self.value = value
... def __eq__(self, other):
... return self.value == other.value
...
>>> b0 = Bar(0)
>>> b1 = Bar(2)
>>> {b0, b1}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'Bar'
At this point, you must implement __hash__
to be consistent with __eq__
, and note, though, that your user-defined object is never really very "immutable"