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?
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
does
let 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 >
:
obj.lval > obj.rval
expression is evaluated>
operator algorithm is run:
lval = obj.lval
(Steps 1 & 2), which causes the "obj.lval was evaluated"
outputrval = obj.rval
(Steps 3 & 4), which causes the "obj.rval was evaluated"
outputARC(obj.rval < obj.lval, leftFirst = false)
obj.rval
as x
and obj.lval
as y
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"
outputfalse
>
operator inverts ARC's return value and returns true
Here's what happens to create the subsequent output for <
:
obj.lval < obj.rval
expression is evaluated<
operator algorithm is run:
lval = obj.lval
(Steps 1 & 2), which causes the "obj.lval was evaluated"
outputrval = obj.rval
(Steps 3 & 4), which causes the "obj.rval was evaluated"
outputARC(obj.lval < obj.rval)
(leftFirst defaults to true)
obj.lval
as x
and obj.rval
as y
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"
outputfalse
<
operator returns ARC's return value, false