Coercion: Deep Dive
Tags: javascript, coercion
Published: 2019-11-23 15:29:11

From the beginning of history of `Javascript`, developers thought that `coercion` is evil and confusing and start to ran away from it. First, let's see what's coercion really.

## Definition
**Coercion**: it's the conversion from data type into another in javascript. It's called in other programming languages *Type Casting*. There's a lot of arguments around this definition, but what I liked is that (Type Casting) is the conversion in statically typed languages like Java & C++, while (coercion) is the conversion in dynamically typed languages like Javascript.

## Types
### Explicit Coercion
It's the conversion from type into another by intention. like:
```js
String(23); // "23"
```

Here we converted the number 23 into string "23" by explicitly calling `String()` constructor. This process is very similar to Type casting in java as we do

`int(23)`

The `String()` constructor uses what's called *Abstract operations* which defined in the specification of the language, `ToString`. These operations is used internally only by the engine and we don't use it in our code. Also, we can use `.toString()` like:

```js
let num = 23;
num.toString(); // "23"
```
or

```js
23..toString(); // "23"
```

As you might saw, when we use the number directly without storing it in a variable, we put extra (.) before `.toString()`, that's because the JS engine consider the first dot as a floating point like we type: 23.5, while the second dot is related to the `.toString()` method.

Also, when we explicitly converting from String into Number we use `Number()` constructor, e.g:
```js
Number("23"); // 23
```

or

```js
let str = "23";
alert(+str); // 23
```

Notice I used `+` operator for explicit coercion from string to number which is a unary operator that get a single operand and converting it into number. The `Number()` uses the abstract operation **ToNumber** which defined in the specification.

#### Explicitly conversion into Boolean
We can convert any non-boolean value into boolean by using surprisingly the `Boolean()` constructor 😅 e.g:

```js
Boolean("23"); // true
```

or we can use `!!` operator:

```js
!!23; // true
```

Notice here we use double `!` as the single ! operator used to convert the value into Boolean then reverse it. Then the second ! reverse the value again as it's reverse the reversion so the result is **true**.

#### Coercion of objects
When we explicitly convert object to any other data type, the engine uses an abstract operation which called **ToPrimitive** that uses `valueOf()` method which convert the object into its primitive value equivalent and if the `valueOf()` fails to get a primitive value then the **ToPrimitive** operation fall back into `toString()` method that converts the object into string which is primitive, e.g:

```js
var a = {
    valueOf: function () {
        return "33";
    }
}

Number(a); // 33

var a = {
    toString: function () {
        return "33";
    }
}

Number(a); // 33

Number([]); // 0
```
In the last example, the array is converted into number which produces 0.

### Implicit Coercion
The second type of coercion is implicit coercion which is the conversion of type without intentionally convert it as it's hidden, non-obvious. This type of conversion confuse a lot of developers and make them avoid it and consider it a bug in javascript.

As the most of developers see implicit coercion evil, I see it from a different perspective as it's used to reduce a lot of boilerplate and details that's unnecessary. As Kyle Sympthon said in his book **YDKJS - Types & Grammar** : *"Don't throw the baby out with the bathwater"*

because the developers see implicit coercion evil they throw it away just to be safe, which is wrong.

Let's see how we can implicitly convert from type to another.

A number is implicitly converted into string by putting it in concatenation expression with a string, e.g:

```js
"2" + 2; // "22"
2 + "2"; // "22"
```

Here the number 2 converted into string by concatenate it with string "2". Let's consider this example:

```js
[2, 4] + [3, 6]; // "2, 43, 6"
```
Wait! What!, confusing hah! No, Not really.

While none of two operand are string the operation produces string. As the ES5 Specification said that when "+" operator receive an object it uses **ToPrimitive** operation which convert an object which is non-primitive into primitive, but which type? Number? or String?

Actually, the **ToPrimitive** operation uses under the hood the **ToNumber** operation which fails to produce a number then it falls back into `toString` method that convert the first array into string `("2, 4")` and the second one into `("3, 6")` then the operation becomes a normal string concatenation:

```js
"2, 4" + "3, 6"; // "2, 43, 6"
```
Obvious, hah!

A string is converted into number by adding the string in mathematical operation, e.g:
```js
let a = "42";

a - 0; // 42
```

#### Implicitly converting from any value into Boolean
This's the most confusing part in implicit coercion. There's cases where implicit coercion to boolean happens:

- Expressions on `if()` statement
- The test expression on `for(;..;)` statement
- The test expression on `while()` loop
- The test expression on ternary operators
- The left hand side in logical operators, `||`, `&&`

```js
let num = 2;

if (num) {
    alert("It's true !"); // It's true !
}
```
Here `num` implicitly converted into Boolean **"true"**, then the test run and the alert fires because the number (2) is a *truthy* value which means it converted into true when put in context of boolean.

You may notice that I said "**The left hand side in logical operators*#", the truth is these operators is not working like you may expect they do similar to other languages like PHP / Java, actually it works differently, so, how is it working ? let's take an example:

```js
let b = 23;
let c = "Hi";

b && c; // "Hi"

b || c; // 23 
```

So, in the first expression, the test goes for the left hand side of the `&&` operator, convert it to boolean - which is truthy - then, return the right hand side. In the second expression the test goes for the left hand side, convert it to boolean - which is truthy also - then return it and doesn't go to the right hand side. This process is called "**Short circuit evaluation**".

The use case for this concept is when you want to return a value depending on truthiness of another value like we do in react, so we use the (&&), also when you want to return a value and provide a *fall back* when the first value is falsy.

```js
// here we check if the array is empty, so don't return any thing or return a paragraphs containing the items of the array
{ arr.length > 0 && arr.map(item => {
    return <p>item</p>;
}) }

// here if the foo() returned undefined or null or any falsy values, the "no value returned" will be returned or the value returned from foo() will be returned either
{ foo() || "no value returned" }
```

#### == vs. ===

```js
2 == "2"; // true

2 === "2"; // false
```

Most of us will respond to this title: "== compares only values while === compares both types and values", actually this's **completely wrong** !

Both of them compares types and values, but the difference is if one of them *permits* `coercion` or not. In the first expression we'll notice that `==` operator permits the coercion from string to number so the result was true, while in the second expression the `===` doesn't permit coercion so the value was **false**.

##### Which is better ?
Other developers will argue wether is better and their teammates will respond: *"of course === because it's much faster than =="*, this's also wrong !

Um, yeah, there's a bit difference in performance but it's not considered because they are very close to each other, so, the final answer is: it doesn't matter which is faster, if you want to permit coercion, use `==`, otherwise use `===`, simply as that.

##### Comparing non-boolean to boolean
The most risky and confusing example that a lot if developers fall in is when comparing any value to true or false. Let's consider this example:

```js

1 == true; // true

"5" == true; // false
```
What ! How come !

The ES5 Spec said:
- **if one of the two operand (x) is boolean return ToNumber(x) and compare them to each other**.
So, when we compare 1 to true the boolean value *"true"* implicitly converted into number which is 1, then `1 == 1` is obviously `true`, while in the second example when we compare `"5"` to `true`, the boolean value implicitly converted into number which is 1 and the `"5"` converted into number which is 5, so, `5 == 1` is obviously `false`.

- **If either side of the comparison can be implicitly converted into true / false, Don't never ever use ==*.

##### Comparing non-objects to objects
If an object is compared to a primitive value the ES5 Spec said:

- **If any one of the two operands (x) is object and the other is primitive, return ToPrimitive(x) and compare them to each other**.
Let's consider this example:

```js

2 == [2]; // true
```
Here the `[2]` converted into its primitive value which is `2`, then compare it to `2` which is obviously `true`.

Simple, hah!

Let's see this example:

```js

false == []; // true

[] == {}; // false
```
In the first example, `false` is converted into number - as we said above - which is `0` and `[]` converted into number by **ToPrimitive** operation which is `0` so the result was `true`, while in the second example, `[]` converted into number by **ToPrimitive** operation which is `0` and `{}` converted into its primitive value which is `NaN` so the result is `false`, as `NaN` never equal to itself or any other value.

Let's see this final example:

```js
[] == ![]; // true
```

Whaaaaaaaaat !

This's completely crazy !

Let's take it from right hand side, the `![]` - by remembering the rules of converting objects - the `[]` is first converted into *boolean* which is `true` then negate it, so, the result of `![]` is **false**, then compare **true** to `[]`, `[] == false`, we saw this before and the result was **true**.

***"If either side of comparison is object, Don't never ever use ==."*** - by `Me`.

## Conclusion
**Coercion** was - for many developers - an evil and confusing concept, it's the conversion from data type into another, it has 2 types, first is the `*explicit coercion*`, which is the intentionally converting from type into another, and `*implicit coercion*`, which is the hidden converting from type into another.

Implicit Coercion hides unnecessary details and simplify the implicitly.

When comparing any value to Boolean or to Object consider not using `==` operator as the coercion here make confusing and unpredicted results.

-