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?

- 209
- 2
- 11
2 Answers
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:
- If the LeftFirst flag is true, then
- Let px be ? ToPrimitive(x, hint Number).
- Let py be ? ToPrimitive(y, hint Number).
- 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 <
operation does:
- 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:
- 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 isLeftFirst true
then why<=
is also notLeftFirst true
and why if>
operator isLeftFirst false
the>=
operator is also notLeftFirst 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:
lval < rval
does:let r = ARC(lval < rval, leftFirst = true); return r === undefined ? false : r; // Returns what ARC returned (but // turns `undefined` into `false`)
lval <= rval
doeslet r = ARC(rval < lval, leftFirst = false); return r === undefined ? true : !r; // Returns the *inverse* of what ARC // returned (and turns `undefined` // into `true`)
lval > rval
does:let r = ARC(rval < lval, leftFirst = false); return r === undefined ? false : r; // Returns what ARC returned (but // turns `undefined` into `false`)
lval >= rval
does:let r = ARC(lval < rval, leftFirst = true); return r === undefined ? true : !r; // Returns the *inverse* of what ARC // returned (and turns `undefined` // into `true`)
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 UsingHere's what happens to create that output for >
:
- The
obj.lval > obj.rval
expression is evaluated - The
>
operator algorithm is run:- It evaluates
lval = obj.lval
(Steps 1 & 2), which causes the"obj.lval was evaluated"
output - It evaluates
rval = obj.rval
(Steps 3 & 4), which causes the"obj.rval was evaluated"
output - It calls ARC (Step 5):
ARC(obj.rval < obj.lval, leftFirst = false)
- ARC recieves
obj.rval
asx
andobj.lval
asy
- ARC sees leftFirst =
false
and so it does:py = ToPrimitive(y)
(Step 2.b), which causes the"lval was passed through ToPrimitive"
outputpx = ToPrimitive(x)
(Step 2.c), which causes the"rval was passed through ToPrimitive"
output
- ARC returns
false
- ARC recieves
- It evaluates
- The
>
operator inverts ARC's return value and returnstrue
Here's what happens to create the subsequent output for <
:
- The
obj.lval < obj.rval
expression is evaluated - The
<
operator algorithm is run:- It evaluates
lval = obj.lval
(Steps 1 & 2), which causes the"obj.lval was evaluated"
output - It evaluates
rval = obj.rval
(Steps 3 & 4), which causes the"obj.rval was evaluated"
output - It calls ARC (Step 5):
ARC(obj.lval < obj.rval)
(leftFirst defaults to true)- ARC recieves
obj.lval
asx
andobj.rval
asy
- ARC sees leftFirst =
true
and so it does:px = ToPrimitive(x)
(Step 1.a), which causes the"lval was passed through ToPrimitive"
outputpy = ToPrimitive(y)
(Step 1.b), which causes the"rval was passed through ToPrimitive"
output
- ARC returns
false
- ARC recieves
- It evaluates
- The
<
operator returns ARC's return value,false

- 1,031,962
- 187
- 1,923
- 1,875
-
but why it will have to do so with the `LeftFirst` Boolean Flag they could have just simpy explianed me this with the `>` – Kevin Mar 21 '20 at 10:28
-
1@Kevin - Using the *leftFirst* flag lets them describe the comparison operation purely in terms of `<`, which apparently they wanted to do. I don't know what the constraints are (which may have changed over time) that made them want to use that vs (for instance) a *lessThan* flag they used in Step 4(k), but there we are... – T.J. Crowder Mar 21 '20 at 10:51
-
so this means that the same `Abstract Relational Comparison algorithm` `expr1 < expr2` is used to compare an operation like `expr1 > expr2` with `LeftFirst` being `false`. simply they use the same `<` operator with an expression like this `expr1 > expr2`. they use the `<` operator instead of `>` operator – Kevin Mar 21 '20 at 11:45
-
1@Kevin - Right. With `expr1 > expr2`, the Abstract Relational Comparison is asked to `expr2 < expr1` instead, but with *leftFirst* = `false`. See the quoted part after *"But the `>` operation does"* above. I've also reworded my paragraph after it to try to make it clearer. – T.J. Crowder Mar 21 '20 at 11:49
-
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` – Kevin Mar 21 '20 at 16:25
-
1@Kevin - Ah, yeah. I've just added something about that, but I think you'd already figured it out. – T.J. Crowder Mar 21 '20 at 16:44
-
But in the specification it's not mentioned that after the `LeftFirst` becomes `false` the right operand is evaluated first for an ex: `10 > 5` is executed `LeftFirst` being false so it's executed like `5 < 10` so in the specification they have not mentioned that the rightOperand(10) is evaluated first before the leftOperand(5) when the `5 < 10` is executed – Kevin Mar 22 '20 at 14:19
-
@Kevin - Yes, they have, in the [sections linked above](https://tc39.es/ecma262/#sec-relational-operators-runtime-semantics-evaluation). Under *"RelationalExpression:RelationalExpression>ShiftExpression"* it says (Step 5) *"Let r be the result of performing Abstract Relational Comparison rval < lval with LeftFirst equal to false."* Then the first two steps of ARC ensure evaluating `lval` first. – T.J. Crowder Mar 22 '20 at 14:27
-
is this only for `objects` or is this rule applied for both `objects and primitives` – Kevin Mar 22 '20 at 14:33
-
1@Kevin - It applies to all operands, but it's only *observable* if those operands are objects; otherwise, it's purely internal and can't be observed. That's because the *initial* evaluation is done in the `>` operation itself. What ARC does is the ToPrimitive operation, which is a no-op if the thing being passed in is *already* a primitive. – T.J. Crowder Mar 22 '20 at 14:36
-
but this user says something different about this i really dunno what here's the link: https://stackoverflow.com/questions/60799820/can-someone-explain-what-exactly-the-leftfirst-booelan-flag-is-in-abstract-re – Kevin Mar 22 '20 at 14:39
-
1@Kevin - No, Pointy is saying what I said above. BTW, here's an example of observing the behavior: https://jsfiddle.net/tjcrowder/n8rfeoza/ But I can see a couple of places in the answer where I said "evaluated," which is a bit imprecise. I've fixed them. – T.J. Crowder Mar 22 '20 at 14:40
-
1@Kevin - I've updated the end of the answer to walk through doing a `>` and a `<`, showing evaluation vs. ToP:rimitive. – T.J. Crowder Mar 22 '20 at 14:56
-
Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/210107/discussion-between-kevin-and-t-j-crowder). – Kevin Mar 22 '20 at 15:05
-
1@Kevin - I think we've covered the ground fairly thoroughly at this point. – T.J. Crowder Mar 22 '20 at 15:16
-
But in the `Abstract Relational Comparison Algorithm` you can see when `LeftFirst` becomes false the right operand operand y is first passed to ToPrimitive before the left operand x is passed to ToPrimitive `If the LeftFirst flag is true, then Let px be ? ToPrimitive(x, hint Number). Let py be ? ToPrimitive(y, hint Number). 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).` can you explain About this a little to me pls it will be great – Kevin Mar 22 '20 at 16:01
-
1@Kevin - Yes, that's right, which is why it exists. Remember that in situations where ARC is called with *leftFirst* = `false`, the operation calling it has *reversed the operands*. In `a > b`, `>` calls ARC with `b < a` (not `a < b`) and *leftFirst* = `false`. That's why it passes that flag, so that `a` is run through ToPrimitive first. – T.J. Crowder Mar 22 '20 at 17:34
-
Do you know why the `Abstract operation` `isStringPrefix(py, px)` returns `false` in ["Abstract Relational Comparison "](https://tc39.es/ecma262/#sec-abstract-relational-comparison) `if isStringPrefix(py, px) is true return false` and can you explain me why the `isStringPrefix()` is used what is it meant to do – Kevin Mar 24 '20 at 15:50
-
1@Kevin - The [definition of IsStringPrefix](https://tc39.es/ecma262/#sec-isstringprefix) seems fairly clear to me: *"The abstract operation IsStringPrefix determines if String p is a prefix of String q."* Its use in the `<` comparison in ARC is to handle `"ABC" < "ABCD"` (which is true) and `"ABCD" < "ABC"` (which is false). Once the algorithm has ruled out one of the strings being a prefix of the other, it goes looking for where they no longer match so it can return the result of comparing the chars that don't match. – T.J. Crowder Mar 24 '20 at 16:01
-
1@Kevin - The IsStringPrefix question there is now *very* far afield from the question you posted and that I answered. For future questions, please post a new question. – T.J. Crowder Mar 24 '20 at 16:02
As the specification says in your link:
The comparison x < y, where x and y are values, produces true, false, or undefined (which indicates that at least one operand is NaN). In addition to x and y the algorithm takes a Boolean flag named LeftFirst as a parameter. 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. The default value of LeftFirst is true and indicates that the x parameter corresponds to an expression that occurs to the left of the y parameter's corresponding expression. If LeftFirst is false, the reverse is the case and operations must be performed upon y before x.
For an example of such a thing, consider two objects being compared. For <
to be performed on them, both need to be coerced to primitives first, and this primitive coercion is permitted to have side effects which could affect the coercion of the other object. It would be weird, but it's syntactically possible, so the specification needs to specify what must happen in such a situation.
Keep in mind that there's only one version of Abstract Relational Comparison, and that's for expr1 < expr2
. There is no separate version for expr1 > expr2
. The LeftFirst
flag is used when invoking Abstract Relational Comparison to indicate which of the expressions should be evaluated first, so that the left-to-right order of operations is preserved.
Here's an example:
let val = 1;
const obj1 = {
valueOf() {
val++;
return val;
}
};
const obj2 = {
valueOf() {
val++;
return val;
}
};
console.log(obj1 < obj2);
Expressions are evaluated left-to-right. obj1
is evaluated before obj2
, so after extracting the primitives, obj1
is less than obj2
.
let val = 1;
const obj1 = {
valueOf() {
val++;
return val;
}
};
const obj2 = {
valueOf() {
val++;
return val;
}
};
console.log(obj2 > obj1);
The obj2 > obj1
actually invokes Abstract Relational Comparison obj1 < obj2
, with LeftFirst
of false
. As a result, the right side, obj2
is evaluated first, because it comes first in the source code.
Intuitively, with left-to-right evaluation, we'd expect
obj2 > obj1
to result in
// evaluate obj2, increment val
2 > obj1
// evaluate obj1, increment val
2 > 3
resulting in false
.
If it weren't for such a flag, the example above would result in obj1
being evaluated first, and the result would be that obj1
would be less than obj2
, and the result of the comparison would be true
. But this is not desirable: the expressions should be evaluated left-to-right.

- 356,069
- 52
- 309
- 320
-
can you give me an explanation about why the `<=` operator is evaluated `LeftFirst` equal to `false` both `<` operator and `<=` operator have a similar typeof symbol like `<` only with one diiference the `<=` operator is having an extra equal to sign `=` but why the `<=` operator is evaluated with `LeftFirst` being `false` similarly if you take the `>` operator it's evaluated `LeftFirst` being `false` but the `>=` operator is evaluated `LeftFirst` being `true` can you give me a clear explanation like the one you gave above why `>=` is `LeftFirst` true and why `<=` is `LeftFirst` false – Kevin Mar 21 '20 at 10:48
-
1Whatever value comes first in the source code gets evaluated first. In the case of `lval <= rval`, because the comparison is sent to Abstract Relational Comparison in *reverse* order (`rval < lval`), `LeftFirst` is `false` so that `lval` gets evaluated first. For `lval >= rval`, because the comparison performed is `lval < rval`, `LeftFirst` defaults to `true`, so that the `lval` will be evaluated first as desired. – CertainPerformance Mar 21 '20 at 11:11
-
so do you mean the `>=` operator is always evaluated `LeftFirst` being `true` – Kevin Mar 21 '20 at 11:52
-
1Yes, because the operation performed for `lval >= rval` is `lval < rval`, so to keep the proper order, leftFirst is true there. Same sort of thing for the other permutations - whatever the situation, Abstract Relational Comparison is called such that the element on the left in the source code is evaluated first. – CertainPerformance Mar 21 '20 at 12:12
-
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` – Kevin Mar 21 '20 at 16:26