Array#sort(prop)

Brendan Eich brendan at mozilla.com
Sun Apr 1 21:59:44 PDT 2012

```Ok, easy goof (I was boarding a plane -- that's my excuse!). But easy to
fix too.

Point is, as Peter posted, this is hard to get right if one has to write
make that the built-in all implementations provide?

/be

Mark S. Miller wrote:
>
>
> On Sun, Apr 1, 2012 at 6:56 PM, Mark S. Miller <erights at google.com
>
>
>
>     On Sun, Apr 1, 2012 at 3:53 PM, Brendan Eich <brendan at mozilla.org
>     <mailto:brendan at mozilla.org>> wrote:
>
>
>         arr.sort((a, b) =>  (a.prop<  b.prop) ?-1 :  (a.prop>  b.prop)
>         ? 1 : 0);
>
>
>         and if you weed out NaN to avoid the comparison function
>         returning NaN, while taking advantage of the fact that the
>         return value's sign is all that matters, not exact {-1, 0, 1}
>         membership, then it's not much worse:
>
>
>         arr.sort((a, b) =>  { let t = a.prop - b.prop; return (t !==
>         t) ? 0 : t; });
>
>
>
>     Quoting from <http://es5.github.com/#x15.4.4.11>, the requirements
>     on the comparefn are:
>
>             A function /comparefn/ is a consistent comparison function
>             for a set of values /S/ if all of the requirements below
>             are met for all values /a/, /b/, and /c/ (possibly the
>             same value) in the set /S/: The notation /a/ <_CF
>             /b/ means /comparefn/(/a/,/b/) < 0; /a/ =_CF /b/ means
>             /comparefn/(/a/,/b/) = 0 (of either sign); and/a/ >_CF
>             /b/ means /comparefn/(/a/,/b/) > 0.
>
>             Calling /comparefn/(/a/,/b/) always returns the same value
>             /v/ when given a specific pair of values /a/and /b/ as its
>             two arguments. Furthermore, Type
>             <http://es5.github.com/#Type>(/v/) is Number, and /v/ is
>             not NaN. Note that this implies that exactly one of /a/
>             <_CF /b/, /a/ =_CF /b/, and /a/ >_CF /b/ will be true for
>             a given pair of /a/ and /b/.
>
>             Calling /comparefn/(/a/,/b/) does not modify the
>             *this* object.
>
>             /a/ =_CF /a/ (reflexivity)
>
>             If /a/ =_CF /b/, then /b/ =_CF /a/ (symmetry)
>
>             If /a/ =_CF /b/ and /b/ =_CF /c/, then /a/ =_CF
>             /c/ (transitivity of =_CF )
>
>             If /a/ <_CF /b/ and /b/ <_CF /c/, then /a/ <_CF
>             /c/ (transitivity of <_CF )
>
>             If /a/ >_CF /b/ and /b/ >_CF /c/, then /a/ >_CF
>             /c/ (transitivity of >_CF )
>
>             *NOTE*
>
>              The above conditions are necessary and sufficient to
>             ensure that /comparefn/ divides the set/S/ into
>             equivalence classes and that these equivalence classes are
>             totally ordered.
>
>
>     If sort is called with a comparefn which violates this constraint,
>     according to normative text
>
>             If /comparefn/ is not *undefined* and is not a consistent
>             comparison function for the elements of this array
>             <http://es5.github.com/#array-element> (see below), the
>             behaviour of |*sort*| is implementation-defined.
>
>
>     a conforming implementation may kill the user, lose memory safety,
>     or launch the nukes.
>
>     Since in this note we're not concerned about new syntax but rather
>     the notion of "implementation-defined", let's rewrite Brendan's
>     two sort functions in ES5:
>
>
>         function c1(a, b) {
>         return a < b ? -1 : a > b ? 1 : 0;
>         }
>         function c2(a, b) {
>         var t = a - b;
>         return t !== t ? 0 : 1;
>
>
> Oops, typo. The "1" immediately above should be "t". But this doesn't
> affect the point.
>
>         }
>
>     Both of these violate transitivity of =_CF
>
>         c1(3,NaN);
>         0
>         c1(NaN,4);
>         0
>         c1(3,4);
>         -1
>         c2(3,NaN)
>         0
>         c2(NaN,4)
>         0
>         c2(3,4)
>         1
>
>
>     Fortunately, I have not tried passing either of these to sort, and
>     so have lived to tell the tale.
>
>     Let's kill "implementation-defined" rather than our users.
>
>
>
>         I'm assuming you don't need to sort -0<  0 (which evaluates to
>         false in JS).
>
>         Another observation: this last version is the only one that
>         avoids multiple implicit conversions via toString or valueOf
>         of an object operand, if one or both of a and b is an object
>         and the first condition (a.prop<  b.prop) evaluates to false.
>         This means the only portable form is the last version.
>
>         Yeah, it's a pain to write every time and people will mess up
>         the NaN corner case. A standard built-in would be good. But
>         why use a string parameter key instead of just a built-in
>         function?
>
>         /be
>
>
>         _______________________________________________
>         es-discuss mailing list
>         es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
>         https://mail.mozilla.org/listinfo/es-discuss
>
>
>
>
>     --
>         Cheers,
>         --MarkM
>
>
>
>
> --
>     Cheers,
>     --MarkM
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
```