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 it from scratch. Finding and downloading a standard library? Why not 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 <[email protected] <mailto:[email protected]>> wrote:



    On Sun, Apr 1, 2012 at 3:53 PM, Brendan Eich <[email protected]
    <mailto:[email protected]>> 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
        [email protected] <mailto:[email protected]>
        https://mail.mozilla.org/listinfo/es-discuss




-- Cheers,
        --MarkM




--
    Cheers,
    --MarkM
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to