javascriptrelational-operatorsecmascript-2020

Can someone explain me what is the "LeftFirst" Boolean flag they have defined in the ecmaScript specification


Can someone explain to me what is the LeftFirst Boolean flag? when reading the EcmaScript specification about [relational-operators](https://tc39.es/ecma262/#sec-relational-operators" relational-operators definition in ECMAScript") and Abstract Relational Comparison I found something like the LeftFirst Boolean Flag it either becomes true or false but I don't know what is the use of it and for what it's there can someone clearly explain me what is the purpose of the LeftFirst Boolean flag and why it is used in the specification the explanation they have given is not much clear I want to know what is the use of it The leftFirst Boolean Flag and why it's used?


Solution

  • As you noted, it's one of the inputs to the Abstract Relational Comparison algorithm. Its sole purpose is to determine which operand the comparison algorithm is passed to ToPrimitive first, the one on the left (leftFirst = true) or the one on the right (leftFirst = false). The reason is that the Abstract Relational Comparison always does a < comparison, but it's also used when evaluating > expressions (with the operands reversed). So when handling a >, it needs to be told to use ToPrimitive on the right-hand operand first.

    You can see it used in the first step of the algorithm:

    1. If the LeftFirst flag is true, then
      • Let px be ? ToPrimitive(x, hint Number).
      • Let py be ? ToPrimitive(y, hint Number).
    2. Else,
      NOTE: The order of evaluation needs to be reversed to preserve left to right evaluation.
      • Let py be ? ToPrimitive(y, hint Number).
      • Let px be ? ToPrimitive(x, hint Number).

    Also in the description:

    The flag is used to control the order in which operations with potentially visible side-effects are performed upon x and y. It is necessary because ECMAScript specifies left to right evaluation of expressions.

    For example, if you look at the < and > operations, the &lt; operation does:

    1. Let r be the result of performing Abstract Relational Comparison lval < rval.

    That uses the default value of leftFirst, which is true. So lval is passed through ToPrimitive before rval.

    But the > operation does:

    1. Let r be the result of performing Abstract Relational Comparison rval < lval with LeftFirst equal to false.

    Notice that it does rval < lval, not lval > rval. But it uses leftFirst = false because it's important that the right operand be passed through ToPrimitive before the left operand, since the real operation is lval > rval, so lval should be passed through ToPrimitive first.


    In a comment you've said:

    Thank you very much i got to know why if < operator is LeftFirst true then why <= is also not LeftFirst true and why if > operator is LeftFirst false the >= operator is also not LeftFirst false

    It's definitely a bit confusing. The reason that < and <= don't match (and > and >= don't match) is that the <=/>= operators invert the result of the Abstract Relational Comparison (ARC). So:


    A a final note, let's consider this:

    const obj = {
        get lval() {
            console.log("obj.lval was evaluated");
            return {
                valueOf() {
                    console.log("lval was passed through ToPrimitive");
                    return 42;
                }
            };
        },
        get rval() {
            console.log("obj.rval was evaluated");
            return {
                valueOf() {
                    console.log("rval was passed through ToPrimitive");
                    return 24;
                }
            };
        }
    };
    
    console.log("Using >");
    const result1 = obj.lval > obj.rval;
    // "obj.lval was evaluated"
    // "obj.rval was evaluated"
    // "lval was passed through ToPrimitive"
    // "rval was passed through ToPrimitive"
    console.log(result1);
    // true
    
    console.log("Using <");
    const result2 = obj.lval < obj.rval;
    // "obj.lval was evaluated"
    // "obj.rval was evaluated"
    // "lval was passed through ToPrimitive"
    // "rval was passed through ToPrimitive"
    console.log(result2);
    // false
    .as-console-wrapper {
        max-height: 100% !important;
    }

    The output you see from that is this:

    Using > obj.lval was evaluated obj.rval was evaluated lval was passed through ToPrimitive rval was passed through ToPrimitive true Using

    Here's what happens to create that output for >:

    1. The obj.lval > obj.rval expression is evaluated
    2. The > operator algorithm is run:
      1. It evaluates lval = obj.lval (Steps 1 & 2), which causes the "obj.lval was evaluated" output
      2. It evaluates rval = obj.rval (Steps 3 & 4), which causes the "obj.rval was evaluated" output
      3. It calls ARC (Step 5): ARC(obj.rval < obj.lval, leftFirst = false)
        1. ARC recieves obj.rval as x and obj.lval as y
        2. ARC sees leftFirst = false and so it does:
          • py = ToPrimitive(y) (Step 2.b), which causes the "lval was passed through ToPrimitive" output
          • px = ToPrimitive(x) (Step 2.c), which causes the "rval was passed through ToPrimitive" output
        3. ARC returns false
    3. The > operator inverts ARC's return value and returns true

    Here's what happens to create the subsequent output for <:

    1. The obj.lval < obj.rval expression is evaluated
    2. The < operator algorithm is run:
      1. It evaluates lval = obj.lval (Steps 1 & 2), which causes the "obj.lval was evaluated" output
      2. It evaluates rval = obj.rval (Steps 3 & 4), which causes the "obj.rval was evaluated" output
      3. It calls ARC (Step 5): ARC(obj.lval < obj.rval) (leftFirst defaults to true)
        1. ARC recieves obj.lval as x and obj.rval as y
        2. ARC sees leftFirst = true and so it does:
          • px = ToPrimitive(x) (Step 1.a), which causes the "lval was passed through ToPrimitive" output
          • py = ToPrimitive(y) (Step 1.b), which causes the "rval was passed through ToPrimitive" output
        3. ARC returns false
    3. The < operator returns ARC's return value, false