This repository has been archived by the owner on Jul 23, 2021. It is now read-only.
Several issues with immutable.is()
#154
Labels
Milestone
From @balagge on Thu, 26 Sep 2019 13:28:45 GMT
NB: see an earlier issue immutable-js#1736 for a specific bug. This is an extension of that ticket.
Since then I discovered some more issues with
immutable.is()
, which is a core function. All equality checks are based on this, and it is called all the time. Therefore, the impact of these problems appears in all immutable.js operations resulting inFalsy values / Falsy
valueOf()
cannot equal to anything else, even if they shouldsee immutable-js#1736 for
0
. However, the same problem existsvalueOf()
. For example, a string-like object:Similar example can be constructed with a custom boolean.
Also, there are 3 more falsy values in javascript, so, unfortunately:
Unexpected result with Date objects
Example:
Here the intended behavior is questionable, but the current behavior above is definitely inconsistent. Probably in this case both should be
false
. The problem is caused by the implementation ofvalueOf()
on Date objects as well as the falsy value problem (valueOf()
returning0
is a separate case).It can be argued that for Date objects
valueOf()
should not be called at all, since the returned value (milliseconds elapsed since1970-01-01T00:00:00Z
) is not "equal" to the Date object. Even more importantly, Date objects are mutable, which can cause serious issues if included in an immutable collection.User defined value objects cannot equal primitive values by
equals()
Suppose you want to implement complex numbers and you want to ensure that any complex number with zero imaginary part is equal to the corresponding real number. However, you do not want to use
valueOf()
- because of the above mentioned problem, you cannot usevalueOf()
consistently. You tryequals()
andhashCode
, and come up with something like this (not actual working code, just idea):Unfortunately this will never work as the
equals()
method is only called if BOTH objects have it:https://github.com/immutable-js/immutable-js/blob/e65e5af806ea23a32ccf8f56c6fabf39605bac80/src/is.js#L84-L88
Bottom line: you cannot implement Complexes with either
valueOf()
, norequals()
consistently.Comparison done twice for all (most) cases (possible performance loss)
If both inputs are objects, then the
valueOf
property check is done. This will almost always be true asObject.prototype
implementsvalueOf
and most user objects will have this in their prototype chain. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOfThe default implementation of
valueOf()
simply returns the object, so the following lines will essentially double-check equality, which has been checked previously:https://github.com/immutable-js/immutable-js/blob/e65e5af806ea23a32ccf8f56c6fabf39605bac80/src/is.js#L71-L83
Probably this is a performance burden as
immutable.is()
is called frequently.Even boxable primitives (number, boolean, string and symbol) are checked twice for equality each time a comparison is made, as these also exhibit a
valueOf()
method after boxing:Suggestion
the implementation of
immutable.is()
should be reconsidered. Ideas:null
/undefined
values, so those must be checked explicitlyvalueOf()
upfront for objects, if exists; do it before comparisons; do not repeat same comparison twicevalueOf()
at all!)equals()
both ways, even if only 1 operand has itThese are just ideas. Since this is a core function, caution is advised, of course.
Copied from original issue: immutable-js#1737
The text was updated successfully, but these errors were encountered: