## Why it’s important to read the Javascript Spec

While compiling notes for a crash course on Javascript I was to give to a couple of colleagues, I came across a rather interesting scenario with nulland relational operators –

null > 0; // false null == 0; // false

null >= 0; // true

Wait…what? That makes no sense!

How can a value **not be greater** than 0, **not be equal** to 0, but be **greater than and equal** to 0?

While I brushed this off initially as just Javascript being Javascript, in all it’s quirkiness, it did intrigue me. Did it have something to do with the type nulland how it is handled, or with how the relational and equality checks are performed?

So I sought out to find the root cause of this and started to sift through the single source of truth for Javascript — The Javascript Spec.

And boy did I go down a rabbit hole!

The Abstract Relational Comparison Algorithm

Let’s take the first check.

null > 0; // false

According to the Spec, the relational operators > and < send the statement through an algorithm called the *Abstract Relational Comparison Algorithm** *to find out if the statement is true or false.

1. Call ToPrimitive(x, hint Number).

2. Call ToPrimitive(y, hint Number).

3. If Type(Result(1)) is String and Type(Result(2)) is String, go to step 16. (Note that this step differs from step 7 in the algorithm for the addition operator + in using 'and' instead of 'or'.)

4. Call ToNumber(Result(1)).

5. Call ToNumber(Result(2)).

6. If Result(4) is NaN, return undefined.

7. If Result(5) is NaN, return undefined.

8. If Result(4) and Result(5) are the same number value, return false.

9. If Result(4) is +0 and Result(5) is -0, return false.

10. If Result(4) is -0 and Result(5) is +0, return false.

11. If Result(4) is +∞, return false.

12. If Result(5) is +∞, return true.

13. If Result(5) is -∞, return false.

14. If Result(4) is -∞, return true.

15. If the mathematical value of Result(4) is less than the mathematical value of Result(5) --- note that these mathematical values are both finite and not both zero --- return true. Otherwise, return false.

16. If Result(2) is a prefix of Result(1), return false. (A string value p is a prefix of string value q if q can be the result of concatenating p and some other string r. Note that any string is a prefix of itself, because r may be the empty string.)

17. If Result(1) is a prefix of Result(2), return true.

18. Let k be the smallest nonnegative integer such that the character at position k within Result(1) is different from the character at position k within Result(2). (There must be such a k, for neither string is a prefix of the other.)

19. Let m be the integer that is the code point value for the character at position k within Result(1).

20. Let n be the integer that is the code point value for the character at position k within Result(2).

21. If m < n, return true. Otherwise, return false.

Let’s walk through this algorithm with our statement – null > 0.

*Steps 1 and 2 *ask us to call ToPrimitive() on null and 0 respectively to convert these values to their primitive value types (such as Number and String). The ToPrimitive conversion follows this table.

Going by the table, both our LHS, null, and RHS, 0, don’t undergo any conversion.

Now *Step 3 *does not apply to us, so we can ignore it and move on. At *Steps 4 and 5*, we need to convert both the LHS and RHS to type Number. The conversion to Number follows this table.

*(I’ve omitted **String** and **Object** from the table as they have a more elaborate conversion, and the conversions are not relevant to us right now anyway. If you are curious about those, you can find them **here**.) *

null gets converted to +0 and 0 remains 0. Neither of the values are NaNso we can skip *Steps 6 and 7. *It’s at *Step 8 *that we need to stop. +0 **is** **equal to**0, and the algorithm returns false. Hence,

null > 0; // false

and

null < 0; // also false

The Abstract Equality Comparison Algorithm

Let’s tackle the next check.

null == 0; //false

This was rather interesting.

The == operator runs the statement through the *Abstract Equality Comparison Algorithm**, and *returns true or false.

1. If Type(x) is different from Type(y), go to step 14.

2.If Type(x) is Undefined, returntrue.

3.If Type(x) is Null, returntrue.

4.If Type(x) is not Number, go to step 11.

5.IfxisNaN,returnfalse.

6.IfyisNaN,returnfalse.

7.Ifxis the same number value asy, returntrue.

8.Ifxis+0andyis-0, returntrue.

9. Ifxis-0andyis+0, returntrue.

10. Returnfalse.

11.If Type(x) is String, then returntrueifxandyare exactly the same sequence of characters (same length and same characters in corresponding positions). Otherwise, returnfalse.

12. If Type(x) is Boolean, returntrueifxandyare bothtrueor bothfalse.Otherwise, returnfalse.

13.Returntrueifxandyrefer to the same object or if they refer to objects joined to each other (see 13.1.2). Otherwise, returnfalse.

14. Ifxisnullandyisundefined,returntrue.

15. Ifxisundefinedandyisnull,returntrue.

16.If Type(x) is Number and Type(y) is String, return the result of the comparisonx== ToNumber(y).

17.If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x)== y.

18. If Type(x) is Boolean, return the result of the comparison ToNumber(x)== y.

19. If Type(y) is Boolean, return the result of the comparisonx== ToNumber(y).

20.If Type(x) is either String or Number and Type(y) is Object, return the result of the comparisonx== ToPrimitive(y).

21.If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x)== y.

22. Returnfalse.

Evaluating the equality of null and 0, we immediately jump from *Step 1* to *Step 14* as the *Types *are not the same. Surprisingly, *Steps 14 through 21 *also do not apply to us, since *Type(x) *is null. We finally arrive at *Step 22* and the value false is returned as a **default**!

Hence,

null == 0; //false

The Greater-than-or-equal Operator (>= )

And now, we get to our last check.

null >= 0; // true

And this is where the Spec threw me off completely. At a very high level, the relational operator >= is evaluated as

ifnull < 0isfalse, thennull >= 0istrue

Hence,

null >= 0; // true

And it makes sense, honestly. Mathematically, if we have two numbers x and y, and if x is *not* *less than* y, then x **has **to be *greater than*, or *equal to *y.

I’m assuming it’s done this way to optimise evaluation of the statement. Why check if x is first greater than y, and if that’s not the case, if x is equal to y, when you can perform just one evaluation — *is **x** less than **y*, and then use the result of that to glean the result for the original evaluation.

*(If you’re curious about the actual steps executed for the **>=** operator, you can find them **here**.)*

As trivial as this problem was, the search for the answer offered up some nice insights to the language. Hope this article did the same for you.

*Source: https://medium.com/@CharlesBordet/how-to-extract-and-clean-data-from-pdf-files-in-r-da11964e252e*

## Leave a Reply