Thursday, May 30, 2013

Weak typing is weak

I spent a couple hours the other day digging through layers of some unfamiliar code to track down a bug that ended up being a really simple, one-line fix. That's nothing spectacular, but this bug had to do with weak typing, which gives me a good opportunity to rant against that. Here was the fix, with some variable names changed to protect the innocent:

--- foo = bar[key] or null +++ foo = if bar[key]? then bar[key] else null

The idea was to get bar[key] if there is such an entry, or else default to null. I recognize that pattern because I've seen it before, and I've written similar code. It's a common pattern; the CoffeeScript page even uses it in an example. (In case you're not familiar with CoffeeScript/JavaScript, the original line works because a or b in CoffeeScript means "a if a is a true value, otherwise b." It's used as a quick get-or-default pattern.)

The problem arises if bar[key] is a defined, useful value that happens to also be a false value — like an integer 0, an empty string, or (to state the obvious), the boolean false. In that case, since the first expression is a false value, the whole expression evaluates to the second expression, null; the original line translated a 0 into a null.

In other words, the problem is that the first expression in a or b doesn't have to be a boolean, it just has to be interpretable as a boolean — and it just so happens that any type in JavaScript/CoffeeScript can be interpreted as a boolean, meaning that it's really easy to use the a-or-b-as-defaulter pattern, which happens to be wrong in many cases. And come to think of it, why are we using the same construct for boolean logic and getter-with-default, which are two completely different concepts?

Here's my issue with that: it's always valid code, and sometimes it's a valid pattern, but the language doesn't tell you when. And that, in a nutshell, is my beef with weak typing.

Now, there are lots of ways to write bugs in code, and it's reasonable to ask why I'm singling out this one class of bugs. I would argue that whereas other bugs are due to misrepresenting a problem, or to applying the wrong solution to a problem, this bug is due to applying the wrong dialect  of the correct solution. Ugh. Debugging is enough of a pain without the compiler encouraging us to write the programming equivalent of a tongue-twister. Weak typing makes it easy to write bugs, and, once you've written them, the type system does absolutely nothing to help you find them.

When it comes to programming, I want the computer to mean what I say. The quid pro quo is that I need to say what I mean. If what I mean is "bar[key] if it exists, otherwise null," then the language should require that I just say that. It's well and good for a language to make that pattern succinct, but blurring the lines between boolean logic and plain-old-values is funky reasoning that can lead to funky bugs.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.