The WHY of WAT

Recently a talk given by Gary Bernhardt at CodeMash has been doing the rounds.  In it, he pokes fun at some apparently crazy behaviours in Ruby and Javascript.

Gary Bernhardt The WHY of WAT

While I might not be able to persuade you that all of the things he complains about make sense, I hope I’ll be able to show you some of the reasons that javascript behaves as it does.

The + symbol

The + symbol in javascript can mean one of three things.

  • It can be an infix addition operator where it operates on two numbers.
  • It can be an infix string concatenation operator where it operates on two strings.
  • It can be a prefix ‘this number is positive’ operator where it operates on a single number.

What makes all of this slightly more complicated is that javascript has automatic type coercion, so if you use something that isn’t a number or a string before or after your + symbol, then javascript is going to automatically convert whatever you did use to be either a string or a number.

  • boolean, null, undefined coerce to a number (true = 1, false = 0, null = 0, undefined = NaN)
  • object, array, function all coerce to a string.

So when you see

[] + [] 

You know that javascript is going to coerce both of those empty arrays to a string and do a string concatenation on them.

When an array is coerced to a string, you get a comma separated list of its contents, so the result will be an empty string.

[] + {} 

In this case, the empty object on the right hand side is again going to be coerced to a string.  Since it doesn’t implement a toString method, it’ll pick up the toString method of the default Object by inheritance which returns the string [object Object] for objects, so we’re concatenating the empty string with the string "[object Object]".

Empty Code Blocks

Now we come to a parsing weirdness in javascript.  You might have spotted that we use curly braces for two distinct things in javascript.  One of them is to indicate code blocks (like after an if statement or as part of a function definition), and the other is to write object literals (JSON as it’s often called).  In some languages code blocks can appear in most places within the code and indicate a new scope.  

Javascript doesn’t use block scoping (yet), but it still allows code blocks to appear inside normal code.  Which means that sometimes when you write {} the javascript parser understands that as an empty code block and sometimes when you write {} it understands that as an empty object literal.  Generally speaking, if the { appears at the beginning of a statement it’s going to be interpreted as a code block. You can force the object literal understanding by wrapping the literal in normal brackets.

{} + []

In this case the empty curly braces are interpreted as an empty code block, which means that the + appears at the beginning of the next statement, meaning that here the + is a prefix operator that indicates a number is positive.  The + prefix operator can only accept a single number argument, so it will always coerce its argument to a number.

In an extra wrinkle, the way javascript coerces an object, a function or an array to a number is via first coercing it to a string. An empty string coerces to 0.  So for example:

+ [] === 0 // because the empty array becomes an empty string which becomes 0
+ [1] === 1 // because the array with 1 in it becomes a string with 1 in it which becomes 1
isNaN(+[1, 2] ) // because the array with 1, 2 in it becomes a string "1,2" which is not a number.
+({toString: function() {return "3"}}) === 3

So an empty object coerces to a string [object Object] which then coerces to NaNwhen it has to become a number for the prefix + operator in the following statement:

{} + {}

The – Symbol

Unlike +, the symbol – is comparatively simples. It only has two meansing, an infix meaning which requires two numbers and a prefix meaning which requires one number. You already know that strings that don’t represent numberbs get coereced to NaN when they are required to turn into numbers, so it should be no surprise that

isNaN("wat" - 1)

Why does this matter?

There are a few aspects of this that can and do come up in ‘real life’.  Back in the bad old days when people used ‘eval’ to parse JSON, they used to have to wrap their JSON in brackets to ensure that the parser didn’t treat it as a code block.  It’s often important to bear type in mind and turn your strings into numbers, because otherwise people will be confused when 3 + 1 = 31.  

Knowing how coercion happens can make a lot of the rules around what == false much less confusing.  And perhaps most importantly of course it’ll let you sit in the audience of a ‘javascript is crazy’ talk (of which there seem to be a few) and act as if it all makes perfect sense to you.

10 thoughts on “The WHY of WAT”

  1. Sounds like a bunch of butt-hurt Javascript programmers in here.
    The reason you don’t think it’s funny is probably because you don’t know any other programming languages and you think Javascript is like teh greatest evrrrrrrrr!!

  2. Even knowing all this, the video was still pretty funny because it pokes fun at the limitations of the primitive operators. The fact that I know where those limitations are doesn’t make it less funny that {} + {} = NaN because it’s like watching a fish try to climb a tree (i.e., pretty damn funny).

  3. It’s funny to programmers who understand how types should and shouldn’t interact with eachother.
    In fact, it’s pretty damn hilarious.
    To those who have never seen anything more than phpbb’s templates and javascript, here are some pointers from one that actually handles types much better:
    >>> [] + []
    >>> {} + {}
    TypeError: unsupported operand type(s) for +: ‘dict’ and ‘dict’
    >>> {} + []
    TypeError: unsupported operand type(s) for +: ‘dict’ and ‘list’
    >>> [] + {}
    TypeError: can only concatenate list (not “dict”) to list
    >>> “wat” – 1
    TypeError: unsupported operand type(s) for -: ‘str’ and ‘int’

  4. wat
    I don’t get it
    Javascript confuses me.
    As for Ruby, it is actually because of the parser.
    When the parser sees
    a = a
    it believes that a was already created.
    Or rather, it seems to not check about it at all. There is probably a reason why this was not changed, probably because it can’t be easily changed.

  5. A related discussion of the presentation.
    It being TDWTF, 90% of the comments were debating what ‘wat’ means and how to pronounce it and the rest were about how the presentation wasn’t funny and the audience sucked.

  6. I knew all of this, and yet the movie was really funny for me. And this just shows how a beautiful language – the JavaScript – can have a really bad syntax (influenced by C/java?), and still can be used globally with success.
    Anyway, these are just funny things a good way to start of finish some trainin session, and you have to remember that every language has some good points and bad points.
    That is why we have coffescript to have a new clean syntax for this great language.

Leave a Reply

Your e-mail address will not be published. Required fields are marked *