Check out a free preview of the full Deep JavaScript Foundations course:
The "Implicit Coercion: Loose Equals" Lesson is part of the full, Deep JavaScript Foundations course featured in this preview video. Here's what you'd learn in this lesson:

Mentioning that the most common complaint against implicit coercion in loose equals, == comparisons, comes from how falsy values surprisingly act when compared to each other, Kyle shows that == operator is used for checking values for equality comparison.

Get Unlimited Access Now

Transcript from the "Implicit Coercion: Loose Equals" Lesson

[00:00:00]
>> Kyle Simpson: I've been promising that we wanna talk about this == thing, cuz it's the elephant in the room. This is the most obvious place where implicit coercion not only enters our programs, but also can bite us. But it only bites us, not because this is a confusing topic that can't be learned, it only bites us because it's unlearned.

[00:00:16] We just haven't chosen to learn what == is about. Guess where the best place to learn what == is about is? Trying it out, reading the spec, that's all I did, okay, there's no magical formula here. What I chose to do was say, if the double equals is so bad?

[00:00:33] Let's test all of the corner cases, and see which ones of them are really bad, versus not actually bad. So I came up, I programmatically generated this list, but I came up with 24 corner case coercions with ==. Far as I'm aware, these are all the corner cases that we can express.

[00:00:53]
>> Kyle Simpson: And I went down the list, and I said, which ones of these are crazy, and which ones of these make sense? And I chose to mark the ones that I thought were strange, this is subjective. But I said, string 0 == false, line 3, that seems strange to me.

[00:01:10] Cuz the string 0 and the value false are most definitely different values. So that results where they end up both becoming numbers, and comparing to each other. That result is strange, should not be, okay,? But by comparison, line 8, false == null, that fails. And that makes a lot of sense to fail, because false and null are distinctly different values.

[00:01:38] And so they aren't equal to each other, you follow me? So if we do the math here, there are 7 of these 24 which are kind of outliers, they are generally WTFs. And there's another 17 of them that actually are pretty reasonable. Your numbers might be slightly different.

[00:01:59] But the point that I'm trying to get at is, supposedly, all of coercion is bad. And it's okay to just get rid of all this implicit coercion, but I kind of think that would be sort of baby with the bathwater here. Cuz it actually looks like most of coercion is pretty good, and there's only a few corner cases that we should be worried about.

[00:02:21] Because there's an infinite number of == coercion comparisons that aren't corner cases, and they're all completely reasonable.
>> Kyle Simpson: So out of the infinite space of reasonable ones, there's only seven which are problematic, that's the point, okay? Let's zero in on those seven, here they are.
>> Kyle Simpson: What do you notice about the first four in that list?

[00:02:51]
>> Speaker 2: False.
>> Kyle Simpson: They're all doing a == comparison with false, right, and I already told you to eliminate those four. So that was pretty easy, we just went from seven down to three. Eliminate those four, and focus on these three in particular, and now let's look at those three.

[00:03:09] When do those kinds of things happen in code? Let's look at the line 6 and line 7, specifically. When is it that we end up doing a double equals comparison with a empty string and an empty array? When can that happen, or when can we compare a 0 to an empty array?

[00:03:27] I decided to test this against my own history of my code, all of the code that I've ever written. I decided to go and try to do some analysis of my code and figure out, are there any places where I do the == and this can happen? And I found very few examples where that's even remotely possible.

[00:03:43] Now, your code may be different. But the point I'm trying to get at is, it's not terribly common that we end up with these logic cases where we could end up comparing an empty string to an empty array. And there's a few places, but it's not every line of code that this happens.

[00:03:58] So even line 6 and line 7, they are corner cases, but they're not common corner cases, they're rare corner cases. So we really just end up back at line 5, the root of all evil, that one empty string double equalling to 0. They all sort of devolve to it, as a matter of fact, line 6 devolves to it, and line 7 devolves to it.

[00:04:22] Line 6 and line 7 happen because of line 5, it really is the root of all evil. And some of you may have seen the WAP video before. It came out several years back, and it was making fun of, in particular, this case. Where the empty array is somewhere coercively equal to the negation of the empty array, that's crazy.

[00:04:40] People that design JavaScript, I don't know what they're smoking, right? So it got a lot of traction from making fun of JavaScript. There is lots of opportunity to make fun of JavaScript when you are ignorant about JavaScript, it's easy. The hard part is to say, hey, wait a minute, why is JavaScript doing that, what part of my understanding is different?

[00:05:03] You know what might be different between me and you? And I mean you metaphorically, the industry as a whole. What might be different between me and you is that when I see something that doesn't make sense, I don't blame the design of the language first. There's a lot of developers that when they see something in JavaScript that doesn't make sense, you know what they do?

[00:05:23] Those idiot designers of that JavaScript language! Because we assume, somehow, that we should be able to look at something and immediately intuit exactly what it's doing, without any learning at all. And if it takes any effort on our part, or if it's confusing in the slightest? We immediately jump to the conclusion, those people don't know what they're doing, designing languages.

[00:05:46] Because my Python, or my Ruby, or my .NET, or fill in the blank of my favorite language doesn't do that. We immediately assume the designers of the language were poor. You know what I assume, there's something wrong with my understanding.
>> Kyle Simpson: I mean, when you come down to it, the source of every bug in every program ever written is actually a lack of understanding.

[00:06:09] This is how I like to say it, at the point where your brain diverges from the way the computer works. It is at that junction point that bugs enter your code. Because if you understood it, you wouldn't write a bug, right? I mean, if you fully understood a piece of code, you'd write it correct.

[00:06:30] So if there was a bug, there must be a lack of understanding. And all I've done is embrace that as a core philosophy of mine. If there's something I don't understand, the problem is on me. Now, I've made plenty of critiques, even today, about design decisions of language.

[00:06:44] But I'm not doing that from a place of ignorance. I'm doing that from a place of, I've studied it deeply, and I've worked with people, and I've become frustrated by it. And by the way, those opinions have changed. There are things that I used to complain about, that I no longer complain about, because now, I understand them.

[00:07:00] And because that was true for myself, I thought. I wonder, if I shared with other people and they learned, maybe they'd complain less, food for thought. So this double, or I mean, this empty array equal to the negation of the empty array. First off, the problem of how absurd that looks comes from a misunderstanding about operators work.

[00:07:26] There's a misunderstanding here, that the operators are gonna happen all at once. Which isn't the case, there is an operator precedence. The negate's gonna happen before the comparison, okay? It's not as obvious, but it's a fact. So what's gonna happen when we negate an empty array? That's a non-primitive, so first we're gonna call the two-primitive on it.

[00:07:47] What's the two-primitive of an empty array?
>> Speaker 2: String.
>> Kyle Simpson: Unfortunately, it's the empty string, it ought to be the string with brackets in it, but unfortunately, it's the empty string. So we have turned it into the empty string, as its primitive. And now, the negate operator says, well, wait, I don't have a boolean yet.

[00:08:06] So I need to take that empty string and turn it into a boolean, everybody with me? So what is the empty string's boolean equivalent?
>> Speaker 2: False.
>> Kyle Simpson: It's false, right, but now, we're in the negate operator, so we're gonna flip it around to true. So now, what we're actually saying is, the empty array == true.

[00:08:29] That's the real comparison that's happening here, everybody with me on that? So the empty array is gonna become the string, and that's gonna become the number 0. And then when we have the array on the other side, which becomes a string, and it becomes a number 0. So now, we compare 0 to 0, we have two occurrences of the root of all evil here, where string became 0.

[00:08:51] If empty string had just became NaN, that wouldn't have happened, okay? So all it takes is to actually dig into understanding operations that occur.
>> Kyle Simpson: Yes?
>> Speaker 2: There was a question on, can you explain why false == null is false? You're saying, if == does a number coercion and both null and false coerce to 0, should the result not be true?

[00:09:17]
>> Kyle Simpson: Yes, except for the fact that there is a special class, there is a special case which, we're gonna look at the spec in a minute. There is a special case in the spec which deals with none, null and undefined, they are treated specially. And importantly, null and undefined are treated as coercively equal to each other, and to no other values in the language.

[00:09:41] So if it was only a numeric coercion that assertion would be true, that would be correct, but there's more to the spec than that.