Saturday, October 13, 2007

Type-Converting Operator Considered Ridiculous

I have come to question the wisdom of the type-converting == operator in JavaScript. The algorithm (defined in §11.9.3 of the ECMA-262 v3 spec) requires no fewer than 22 steps to execute, and produces such amazing intrasitivities as:

>>> '0' == 0
true

>>> 0 == ''
true

>>> '' == '0'
false

and random quirkiness such as:

>>> ' \t\r\n' == 0
true

but:

>>> null == 0
false

>>> null == false
false

>>> null == ''
false

>>> null == undefined
true

Do these behaviors strike anyone else as, well, a bit off? In the first example (discussed elsewhere) the intransitivity of the equality operator is a result of wanting an equality operator to play well within a weakly-typed language. If you want to be able to compare numbers to their string representations as though they were of the same type, while still preserving string comparison, this is the logical result. The second example is a result of the ToNumber algorithm, described in §9.3ff. The whitespace conversion to number value 0 is strange, but defined in the spec (in fact, it's a result of the same algorithm that dictates Number(' ') => 0). The third example seems bizarre as well; I'm not sure why null would be treated differently than 0 or false, but the same as undefined, in such expressions. Many articles from otherwise reputable sources often describe all of these values in terms of "truthiness" and "falsiness", but these articles sometimes gloss over these distinctions.

I don't condone transitioning JS into a strongly-typed system, but some of these behaviors are quite subtle. Given the fact that the vast majority of JavaScript programmers seem to be unaware of the strict-equality operator === (and its negative counterpart, !==), it's no wonder behaviors such as these can cause confusion. See also this article for even more pitfalls, this time simply with math operators combining string and numeric types.

So as Crockford says, use the strict comparison operator === unless you know what you're doing.

Thursday, October 4, 2007

All the Code Security You Need

Lots of beginning JS coders seem to have this idea that the web is all about having your cake and eating it too. I want to participate in the glorious Internet revolution, I just don't want to share my ideas or information with anybody else. I'm writing rich internet applications that are so great, just so unique, that I want to make sure nobody else can possibly look at my code and steal all those great juicy super-awesome proprietary ideas I've got. And maybe, just for bragging rights, I want my files to look HUGE as well. I've mocked up a handy little device that can take care of both tasks at once. Behold, the decompressJS module:

var decompressJS = (function () {
    var encoding = [' ', '\t', '\n', '\r'];
    var revEncoding = (function () {
        var ec = {};
        for (var i=0; i<encoding.length; i++) {
            ec[encoding[i]] = i;
        };
        return ec;
    })();

    return {
        encode: function (codeText) {
            var out = [], cc, i=0, len=codeText.length;

            while (i<len) {
                cc = codeText.charCodeAt(i++);

                // JS chars are actually 16-bit UTF-16 chars, 
                // so we need 4 chars encoded per source char
                // to fully encode
                for (var j=0; j<8; j+=2) {
                    out.push(encoding[(cc>>j)&3]);
                }

            }
            return out.join('');
        },

        decode: function (encodedText) {
            var out = [], cur, i=0, len=encodedText.length;
            while (i<len) {
                cur = 0;
                for (var j=0; j<8; j+=2) {
                    cur += revEncoding[encodedText.charAt(i++)]<<j;
                }
                out.push(String.fromCharCode(cur));
            }
            return out.join('');
        }
    };

})();

Like any mature programming paradigm, my decompressJS can even effectively encode and decode itself, the above 1225-character-long code example (including whitespace) decompressed neatly into an all-whitespace string with no fewer than 4900 characters! Just run your code through this baby and it'll come out the other end fully converted into only invisible whitespace characters! Transfer your JS code over the wire, making it look like nothing but an empty file with all whitespace! Magically increase your file size by a factor of 4! Impress your colleagues with your invisible code! Who's laughing now, code stealers?