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

hx.sort.compare treats `undefined` and `null` as normal strings #372

Closed
jonthans opened this Issue Jan 12, 2017 · 2 comments

Comments

Projects
None yet
2 participants
@jonthans
Copy link
Contributor

jonthans commented Jan 12, 2017

Context

using hx.sort.compare to compare strings with undefined or null values

Expected Behavior

hx.sort.compare("m", null)
// 1

hx.sort.compare("o", null)
// 1

hx.sort.compare("t", undefined)
// 1

hx.sort.compare("v", undefined)
// 1

hx.sort.compare(null, undefined)
// 0

hx.sort.compare(undefined, null)
// 0

I'd mainly expect undefined or null values to be compared consistently and not according to their string representation. Whether or not the comparison of a defined value with undefined or null returns -1 or 1 is up for debate.
The last two examples may be debatable as well, if you want to prioritise one over the other.

Actual Behavior

hx.sort.compare("m", null)
// -1

hx.sort.compare("o", null)
// 1

hx.sort.compare("t", undefined)
// -1 

hx.sort.compare("v", undefined)
// 1

hx.sort.compare(null, undefined)
// -1

hx.sort.compare(undefined, null)
// 1

Possible Fix

Check for whether or not each value is defined in the comparison.

Steps to Reproduce

  1. go to https://www.hexagonjs.io/
  2. run above commands in the browser console

Your Environment

  • Hexagon Version: 1.9.0
  • Browser Name and version: Chromium 55.0.2883.87, Firefox 50.1.0
  • Operating System and version (desktop or mobile): Ubuntu 16.04 (64-bit)
@c-frater

This comment has been minimized.

Copy link
Contributor

c-frater commented Jan 13, 2017

When using native Array::sort, undefined values are never passed to hx.sort.compare, however null values are:

['z', undefined].sort(hx.sort.compare)
// ["z", undefined]

['z', null].sort(hx.sort.compare)
// [null, "z"]

This produces the same behaviour as native sorting:

['z', undefined].sort()
// ["z", undefined]

['z', null].sort()
// [null, "z"]

From the spec, undefined values are explicitly not passed to the compare function:

1. If x and y are both undefined, return +0.
2. If x is undefined, return 1.
3. If y is undefined, return −1.
4. If the argument comparefn is not undefined, then
...

If we make this change, we should behave as the spec suggests:

Because non-existent property values always compare greater than undefined property values, and undefined always compares greater than any other value, undefined property values always sort to the end of the result, followed by non-existent property values.

From my understanding, this would result in:

hx.sort.compare(undefined, undefined)
// 0

hx.sort.compare(undefined, _)
// 1

hx.sort.compare(_, undefined)
// -1

hx.sort.compare(null, null)
// 0

hx.sort.compare(null, _)
// 1

hx.sort.compare(_, null)
// -1

[null, undefined, 'a', null, 'nil', undefined ,'undr', undefined, null, 'z', 'b'].sort(hx.sort.compare)
// ["a", "b", "nil", "undr", "z", null, null, null, undefined, undefined, undefined]

This is contrary to how the native sort would perform:

[null, undefined, 'a', null, 'nil', undefined ,'undr', undefined, null, 'z', 'b'].sort()
// ["a", "b", "nil", null, null, null, "undr", "z", undefined, undefined, undefined]

We possibly only want to handle undefined values in the same way as they are done in the native Array::sort function and leave null values to behave as they do currently (as this would not cause [..].sort(hx.sort.compare) to change).

If we were to add the null behaviour, I would suggest doing it as part of a Major release (or under a separate function? e.g. hx.sort.nullCompare)

@jonthans

This comment has been minimized.

Copy link
Contributor

jonthans commented Jan 13, 2017

Having a separate compare function to keep the current behaviour consistent sounds good. I'd suggest calling it hx.sort.compareNullsLast.
So there are effectively two things to do then:

  1. adjust the comparison behaviour for undefined to always compare greater
  2. add a function that treats nulls (almost) like undefined

@jonthans jonthans referenced this issue Jan 29, 2017

Merged

#372: added hx.sort.compareNullsLast #383

4 of 6 tasks complete

@jonthans jonthans self-assigned this Jan 29, 2017

@jonthans jonthans added the In Review label Jan 29, 2017

c-frater added a commit that referenced this issue Feb 28, 2017

@c-frater c-frater removed the In Review label Feb 28, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment