Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deepEqual returns true for different dates #1118

Closed
nidu opened this issue Jul 28, 2017 · 15 comments
Closed

deepEqual returns true for different dates #1118

nidu opened this issue Jul 28, 2017 · 15 comments
Labels

Comments

@nidu
Copy link
Contributor

nidu commented Jul 28, 2017

Hello.

MobX mobx.extras.deepEqual returns true when comparing two different Date objects. Probably just comparing dates deeply is meaningless but they are compared this way being attributes of some other objects.

jsfiddle, example from node console:

> mobx.extras.deepEqual(new Date('2016-01-01'), new Date('2017-01-01'))
true

MobX 2.70, 3.2.2. Didn't check other

Note: initially spotted when working with moment. When two moment instances created from Date objects are compared - they are equal as well.

@urugator
Copy link
Collaborator

Check the comment

@nidu
Copy link
Contributor Author

nidu commented Jul 28, 2017

@urugator i'm using MobX 2.7.0 at the moment. Does it mean i can't use asStructure modifier in reaction when there are dates in compared structures by design?

@urugator
Copy link
Collaborator

Dates aren't plain structures, therefore they may not be structuraly comparable...
I have a feeling that someone reported that structural comparator works for dates, but it has been some time, so it could have changed. It really depends on the Date implementation, so I wouldn't rely on it.

@nidu
Copy link
Contributor Author

nidu commented Jul 28, 2017

@urugator Agree that they are not meant to be structurally compared. However they can be attributes of objects which are structurally compared. I suppose easy fix would be just to make a special case in deepEqual for dates.

@urugator
Copy link
Collaborator

urugator commented Jul 28, 2017

However they can be attributes of objects which are structurally compared.

Can be said about a lot of built-ins (Element, new Number, new Boolean), making a special case for each probably isn't a solution. (I agree the Date is the most common one)
Someone may actually expect false (i would) on the same dates, because they are different instances. (Not very practical, but consistent behavior)
Also note that a lot of ppl use non-standard Date implementations (momentjs). (Another special cases?)
I quess it would be a breaking change, so it wouldn't get into 2.x.
In 3.x you can define own comparator.

@nidu
Copy link
Contributor Author

nidu commented Jul 28, 2017

@urugator not sure there are too much builtins and handling them may not be that cumbersome (not sure Element should be treated though). And yeah, special cases are special cases, they.

About expecting false: it's not obvious behavior when you compare two different objects and they are equal. Date is special (i'd say it's close to primitive type) and should be treated specially. deepEqual saying that two different dates are equal is just a implementation detail. If dates were represented as objects with year/month/day/... fields deepEqual would behave different though these are the same dates.

About momentjs - that's not a special JS case so i don't think it requires special case in MobX. If it uses Date - it would benefit as well consequently.

@urugator
Copy link
Collaborator

Maybe structural comparator should call valueOf before performing the comparison?

@nidu
Copy link
Contributor Author

nidu commented Jul 28, 2017

Sounds like a nice idea

@mweststrate
Copy link
Member

Since recently computed and reaction support custom comparison functions, so I think there is no need to further extend mobx for this.

@urugator
Copy link
Collaborator

urugator commented Sep 5, 2017

@mweststrate
At least for the next Mobx version, I would really consider calling valueOf in comparer.structural.
The behavior would imho better reflect the purpose of structural comparator, which is to treat compared things as value like objects
valueOf is a standard way to make arbitrary types comparable exactly in this manner.
I can't imagine a situation where it would be undesirable.

@mweststrate
Copy link
Member

mweststrate commented Sep 5, 2017 via email

@urugator urugator mentioned this issue Sep 5, 2017
14 tasks
@urugator
Copy link
Collaborator

urugator commented Sep 5, 2017

Btw it also plays well with boxed values - currently the deepEquals fails on the same boxed values (quite unexpected tbh):

const Mobx = require("mobx");
const box1 = Mobx.observable(5);
const box2 = Mobx.observable(5);
console.log(Mobx.extras.deepEqual(box1, box2)); // false
console.log(Mobx.extras.deepEqual(box1.valueOf(), box2.valueOf())); // true

@mweststrate
Copy link
Member

Also note that MobX is just following the general consensus here on what "deep equality" means:

// Jest:
expect(new Date("2016-01-01")).toEqual(new Date("2017-01-01")) // false

// Object.is:
Object.is(new Date("2016-01-01"), new Date("2017-01-01")) // false

// Lodash:
_.isEqual(new Date("2016-01-01"), new Date("2017-01-01")) // false

Also note that all api's in MobX that use comparision allow customizing the equals function that is used, so you can still define a comparer in your code base that works as you want.

@mweststrate
Copy link
Member

mweststrate commented Feb 27, 2018

Ok, this is funny (not). Somehow this entire conversation is based on me reading:

"deepEqual should return true for same dates"

and

mobx.extras.deepEqual(new Date('2016-01-01'), new Date('2016-01-01'))

Sorry folks!

Which also kinda kills the examples because I copy pasted them wrong :-/.

@mweststrate
Copy link
Member

Released as 3.6.0. I feel quite embarrassed for leaving this issue unsolved for halve a year but not correctly understanding it :)

Also, the new algorithm is quite literally taken from underscore. Nice benefit is that dates are now treated as primitives so two Date objects with the same date yield true.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants