Billion-dollar mistake(s)!
In the Javascript world & how to deal with them
What are the billion-dollar mistakes in the software world?
- Y2K bug, a class of bugs related to the storage and formatting calendar data, was estimated to cost a little less than 4 billion dollars according to Tony Hoare.
- CodeRed Virus, a computer worm that infiltrated world-wide companies, brought down all the networks. The interruption to business and all the ordinary banking, other business was estimated to cost the world economy 4 billion dollars.
- Null is the misguided invention of British computer scientist Tony Hoare (most famous for his Quicksort algorithm) in 1964, who coined his invention of null references as his “billion-dollar mistake”.
Who coined “null” a billion-dollar mistake & why?
I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years. — Tony Hoare
A null pointer reference could be a bad idea. Comparing a null pointer reference to a promiscuous adulterer he noted that the null assignment for every bachelor represented in an object structure “will seem to be married polyamorously to the same person Null. — Edsgar Djikstra
What is/are billion-dollar mistake(s) in the context with Javascript world?
We have two candidates in Javascript world falls under this category:
1⃣️ Null
The value null
is written with a literal: null
. null
is not an identifier for a property of the global object, like undefined
can be. Instead, null
expresses a lack of identification, indicating that a variable points to no object. In APIs, null
is often retrieved in a place where an object can be expected but no object is relevant.
2⃣️ Undefined
undefined
is a property of the global object. That is, it is a variable in global scope. The initial value of undefined
is the primitive value undefined
.
Javascript’s primitive datatypes(ES2020),
Boolean
Null
Undefined
Number
String
BigInt
Symbol
Null and Undefined in Javascript called “Nullish”(falsy) values.
Falsy Values:
Undefined, null, 0, NaN, empty string‘’, false
Null vs Undefined
Despite the behaviour for both being falsy values, if one is thinking Null vs Undefined
as Declared vs Undeclared
, not really!
Undefined can be for both declared and undeclared.
What about Null?
Null has it’s own issues to deal with.. great! Let’s look at that,
Well, typeof null == “object”
is a 25 year old bug, since the first version of Javascript.
In the first version of JavaScript, values were stored in 32 bit units, which consisted of a small type tag (1–3 bits) and the actual data of the value. The type tags were stored in the lower bits of the units. There were five of them:
000: object
. The data is a reference to an object.001: int
. The data is a 31 bit signed integer.010: double
. The data is a reference to a double floating point number.100: string
. The data is a reference to a string.110: boolean
. The data is a boolean.
From the original source code jsapi.h
, (link)
#define JSVAL_OBJECT 0x0 /* untagged reference to object */
#define JSVAL_INT 0x1 /* tagged 31-bit integer value */
#define JSVAL_DOUBLE 0x2 /* tagged reference to double */
#define JSVAL_STRING 0x4 /* tagged reference to string */
#define JSVAL_BOOLEAN 0x6 /* tagged boolean value */
Two values were special:
undefined(JSVAL_VOID)
, is int minus(-) JSVAL_INT_POW2(30), that is, a number outside the integer rangenull(JSVAL_NULL)
, is the machine code NULL pointer, an object type tag plus a reference that is zero(OBJECT_TO_JSVAL(0))
.
#define JSVAL_VOID INT_TO_JSVAL(0 - JSVAL_INT_POW2(30))
#define JSVAL_NULL OBJECT_TO_JSVAL(0)
#define JSVAL_ZERO INT_TO_JSVAL(0)
#define JSVAL_ONE INT_TO_JSVAL(1)
#define JSVAL_FALSE BOOLEAN_TO_JSVAL(JS_FALSE)
#define JSVAL_TRUE BOOLEAN_TO_JSVAL(JS_TRUE)
Now, when examined its type tag and the type tag said “object”. (source)
- Line# 10, first checks whether the value
v
isundefined(VOID)
. - Next check at line# 12, checks for is object
JSVAL_IS_OBJECT
, - Additionally, calls for Function Class (line# 18, 19)
- And hence evaluates to
Object
- Subsequently have checks for number, string, and boolean, not even a check for Null
Might be one of the reason, where the first version of JavaScript completed in 10 days. Later on, continued to live with this issue rather than fixing due to its tightly coupled logic in the original source code. Fixing would lead to breaking lot of things in the code.
Dealing with Null & Undefined
From ES2020, we have better way of handling “Nullish” values in Javascript. For current projects, the same can be achieved with the support of Babel.js and/or Typescript.
- Optional Chaining (?.)
Also known as Safe evaluation or Safety operator
Long chains of property accesses in Javascript are lead to errors causing crashes as one might yield null
or undefined
(“nullish” values
). Checking for property existence in a deeply-nested structure is a tedious task, for e.g., consider a weather api response,
In order to fetch the value “Thunderstorm” details, the three approaches,
Now, from ES2020
or TypeScript 3.7
or @babel/plugin-proposal-optional-chaining
supports optional chaining, where one can write like this,
- Nullish coalescing (??)
The Nullish Coalescing operator(??
) acts very similar to the ||
operator except that we don’t use falsy values but nullish, meaning is the value strictly equal to null
or undefined
Supported with ES2020
, Typescript 3.7
and @babel/plugin-proposal-nullish-coalescing-operator
Avoid Null in all possible ways
NullObject Pattern
❌ WRONG
✅ RIGHT, NullObject Pattern
Final Words
(courtesy: Maxmilliano Contieri)
Programmer use Null as different flags. It can hint absence, an undefined, a value, an error, or a falsy value (“Nullish”
value). Multiple semantics lead to coupling errors.
Problems
- Coupling among the callers and senders
- Mismatch among the callers and senders
- If/Switch/case polluting
- Null is not polymorphic with real objects, hence
NullPointerException
(TypeError: null or undefined has no properties
) - Null does not exist on real world. Thus it violates Bijection principle
Solutions
- Avoid Null
- Use Null Object Pattern
- Use optionals
Exceptions
- APIs, Databases, external systems where NULL does exist
Linter support
Add no-null
and no-undef
to your .eslintrc
Sound Null Safety
The Modern languages introducing Sound Null Safety or otherwise known as Void Safety for safer and maintainable code, meaning by default the language assumes the variables are non-null values unless explicitly specified otherwise.
When you opt into null safety, types in your code are non-nullable by default, meaning that values can’t be null unless you say they can be. With null safety, your runtime null-dereference errors turn into edit-time analysis errors.
For e.g., Dart, Swift to name a few follow Sound Null Safety