2011.11.04

Trust no Strings

Been delaying to write this post for a long time, I think it’s something that experienced developers or people coming from strong typed languages like Java or C# probably already know what I’m going to talk about but for JavaScript developers I think it will be an important information since everyday I see someone (or some famous open-source project) doing it “wrong”.

Strings are evil

Strings are error-prone, a small typo error and your application won’t work as expected and the compiler/environment/VM/etc probably won’t give you any error messages, consider the code below:

    calendar.showMonth('feburary');
    calendar.dispatchEvent('monht/show');

Did you noticed something wrong? “February” and “month” were misspelled, depending on how the code is written you won’t see any error message and have no idea why the month isn’t being displayed and why the event listener isn’t being called…

Constants

Because of this kind of error that a lot of people started creating pseudo-constants to store string values, numbers, etc…

    var FEBRUARY = 'february',
        ON_SHOW_MONTH = 'month/show';
    ...
    calendar.showMonth(FEBURARY); //error since var FEBURARY is not defined.
    calendar.dispatchEvent(ON_SHOW_MONTH);

By using a pseudo-constant (JavaScript doesn’t have real constants) the code above will throw an error telling that FEBURARY doesn’t exist. You don’t need to spend 1 hour trying to find out what went wrong, it takes less than 1 minute to spot the error, if you are running JSLint/JSHint during each file save (highly recommended approach) it would display the error without even needing to run the code (extra bonus).

“Errors should never pass silently. Unless explicitly silenced.” – The Zen of Python

Another advantage is that code completion will probably work better so you won’t mistype the constant name and don’t even need to type the whole word/sentence since it will auto complete it for you.

Readability

On many languages (PHP/Java/C#/etc..) a lot of settings are stored as integers, they create constants for each one so a value that may be unreadable like showError(5045) becomes readable showError(WRONG_INPUT).

“It’s harder to read code than to write it. This is why code reuse is so hard.” – Joel Spolsky

Maintainability (added 2011/11/05)

If for some reason you need to update the value you just need to change it on a single place, it will avoid code duplication and errors introduced by updates. You also concentrate all the important info and settings, making it easier to update. Having strings spread over your whole code base is usually a sign of code that is hard to maintain (specially if same value appears in multiple places).

Beware! (added 2011/11/05)

    var MONTHS = {FEBRUARY : 'february'},
        EVENTS = {SHOW_MONTH : 'month/show'};
    ...
    calendar.showMonth(MONTHS.FEBURARY); // `undefined` (no error thrown)
    calendar.dispatchEvent(EVENTS.SHOW_MONTH);

As spotted by Arieh in the comments, accessing non-existent properties of an object returns undefined without throwing any errors. Make sure you validate the passed values to check if they do exist and are valid (trust no strings).

Constants are better but not the definitive solution

Constants solve the problem but they are also verbose and can be tiresome to create it for every single value… Another option is to create specific functions and properties for each existing option, e.g.:

    //can be just an alias to a "private" method `_showMonth(name)`
    //it can even be automatically generated (since JS is a dynamic language)
    calendar.showFebruary();

    //created an object "on" to store all the event types
    calendar.on.showMonth.dispatch();

Another option is to use integers when it does make sense (not as safe but harder to mistype and usually easier to validate):

    calendar.showMonthByIndex(1);

PS: “indexes” always starts at zero (like array indexes), if the value should start at 1 use the word “number” showMonthByNumber(2).

More

So remember, every time you pass strings to functions or write code that relies on strings consider if using a constant or creating a new method wouldn’t be a safer approach (specially if it is a public method) or make sure you provide error messages if the user passes the wrong values. Code compressors like Google Closure Compiler and UglifyJS will usually inline the constants or shorten their names so file size isn’t an issue in most cases.

This kind of silly error was one of the main reasons why I decided to code JS-Signals. After I started using Signals the amount of stupid errors related with typing decreased a lot, I already knew that strings were evil for a long time and been using constants for all my AS3 events but in JS sometimes I was just taking the “shortcut” and using strings for things that should be constants…

Code in a way that will reduce the chance of errors and that will make code more readable, if you feel you are typing too much you are probably using the wrong editor or not coding on a way that helps your work flow… - I enabled word completion on Vim to all the words on any opened file so typing showMonth and showMonthByIndex takes about the same time if it is already defined…

This presentation by Douglas Crockford is really good and point some common errors that made him create JSHint.

“There will be bugs. Do what you can to move the odds to your favor.” – Douglas Crockford

Good coding and always remember: Strings are evil.

Related

Edit: Fix constant examples, add info about accessing undefined object properties and maintainability.


Comments

Actually, using JS "constants" is as error prone as strings, as typos will not raise errors. Consider the following - var months = [ array of months ]; var NAMES = { JANURARY : 0 }; function getMonth(i){ return months[i]; }

console.log( getMonth(NAMES.JANURRAY) ); //typo (fiddle: http://jsfiddle.net/DduEL/ ) this will log undefined, just as doint console.log("janrurrary"); would - because in JS undefined is a valid value. Only trying to access members of undefined will rais errors (NAMES.BLA.a). The only "advantage" of constants is code visibility. IMO in 90% of cases this is a habit that was transported to JS from Java devs that has no real place in it (the habbit - not the devs :) )

Arieh, you are right, I updated the example to use an object to be more "organized" (before it was using separate variables for each value), but again, if value is undefined it is probably an error since you expect a string and it should be a valid string (trust no strings, even if using "constants"). My other comments about code completion and making code readable are still valid, and depending on the code structure (or if you are validating the values as you should) than it would still throw an error somewhere. - I just reverted the example to previous version so now it will throw errors. thanks for spotting it. (trust no code samples)

About constants not having a place in JavaScript I disagree... Having strings spread across your whole source code is bad for maintenance as well... Yesterday I spent 4 hours debugging a massive PHP+JS project that wasn't coded by myself and the error was a missing "s" on the middle of a string (by coincidence) the developer had the same value scattered over his whole codebase so he probably forgot to update it everywhere, if he had stored the value on a variable and reused it everywhere I wouldn't need to spend 4hs trying to find where the problem was since the problem wouldn't exist. It's not only about raising exceptions but code duplication and maintainability as well.

Once again thanks for spotting the error, another reason to not trust developers, sooner or latter they will make stupid mistakes no matter how experienced they are... - yes, I knew this behavior and if it was somebody else blog I would probably spot it.. was focused on the copy itself and didn't realized the example was wrong - Cheers.

As someone who develops free open-source artificial intelligence (AI) in JavaScript and in Forth, I find it unsettling that programmers I talk to expect me to use strings to hold English words, when my AI theory requires me to use single ASCII characters sequenced in an array instead of strings. In the Forth programming language, strings are a big problem, so I am glad that my MindForth AI uses no strings at all, but still stores and retrieves and thinks with English words. Likewise in JavaScript the Mentifex AI Mind appears to be using strings when it thinks, but it is really reactivating not strings but sequences of character-engrams. (Just my two cents worth :-)

Well said.

Leave a Comment

Please post only comments that will add value to the content of this page. Please read the about page to understand the objective of this blog and the way I think about it. Thanks.

Comments are parsed as Markdown and you can use basic HTML tags (a, blockquote, cite, code, del, em, strong) but some code may be striped if not escaped (specially PHP and HTML tags that aren't on the list). Line and paragraph breaks automatic. Code blocks should be indented with 4 spaces.