2013/01/07

Start Simple - Equivalence is NOT Equality

If you, like me, come from a curly-brace language, Javascript has some surprises for you. And not all of them are nice.

One of the first face-palm moments I had with Javascript was with the equality operators. Or what I thought were the equality operators. Because, you see, in C++ and C#, == means "is equal to" and != means "is not equal to". And they are type-safe, so you can't easily shoot yourself in the foot (unless you overload them).

So you happily start using them churning out validation code until you realize there is something wrong - comparisons sometimes work, but sometimes don't. And they are not always transitive. What's is going on?

First, you have to be sure that you are comparing apples to apples. Are you really comparing numbers to numbers? Look closer:

Hmm. So comparing a number to its string representation works - magically. Neat, you think, it simplifies code. Then what about
Hey, that's really neat - automatic type conversion. But what if I don't want it? Is there a way to get rid of it?

Turns out there is. Because these two operators are not testing equality - instead they are testing equivalence.
In general numbers are equivalent to their string representation (as is NaN), but dates (Date objects) are not. null is equivalent to undefined but to nothing else.

Now, if I want true equality, there is one solution - the triple equal (===) and its triple non-equal buddy (!==). The previous examples then become


Next time you are chasing weird validation bugs, think whether:

  • you are comparing the right things (numbers to numbers)
  • you are comparing what matters (actual value vs string representation).
Rules of thumb to decide which one to use (work for me, feel free to use them or leave them)
  • Good candidates for equivalence are cases where type conversion does not matter or is even welcome. Think integer-to-float comparisons. null-to-undefined is also a good candidate.
  • Think hard what kind of input you receive in your routines. If it is whatever jQuery's val() is returning, you are better off parsing it to the target  type first and then deciding which one of the two approaches is best.
  • In general avoid comparing anything to strings (unless it is also a string).
A lot of bugs and confusion can be avoided if you remember - equivalence is powerful, but it is not transitive. If a == b and b == c, it does not mean that a == c.
Equality is strict, but it is often more straight-forward, with less nasty surprises. And yes, if a === b and b === c, you are guaranteed that a === c.

No comments:

Post a Comment