The Difference Between a Compiler and a Compressor

closure
With the release of Google's Closure Tools comes the perennial misunderstanding of what a compiler is. When we have a compiler that takes in C or C++ code (pick your poison) and produces machine code for a particular chip, it's clear that the output is not the same as the input. But when you have a JavaScript to JavaScript compiler that' supposed to make the resulting code more "efficient," it may be tempting to think of it as something just like a compressor, like Packer.

What does Packer do? It compresses your code by transforming it into something that uses fewer characters, then, at run time, it uncompresses and evaluates it (eval()). The actual logic, branching statements and variables don't change, just as a Word document compressed with Zip doesn't change. The benefit is that on download, the code is smaller.

With an optimizing compiler, your code is actually modified to make it smaller and, hopefully more efficient. For example, if I've got a bit of code like this in my JavaScript:

if (false) {
  // big heaping chunk of JavaScript
}

Packer will happily compress and uncompress this bit of code, even though it will never be executed. An optimizing compiler, on the other hand, will just cut this whole chunk of code out. Well, that's not so hard, right. Look for conditional with false in them and cut those out. What if the code looks like this?

var always = false;
if (always) {
  // big heaping chunk of JavaScript
}

Now your compressor has to realize that always will always be false. It can get even more complicated than this of course, at which point to cut out dead code you have to model what the code is going to do to get all of the things like conditional that always evaluate to a constant. Well, that's part of what an optimizing compiler does, as opposed to a simple compressor.

Another type of optimization comes from making loops more efficient. For example, take the following code:

var total = 0;
var i;
for (i=0;i<=100;i=i+1) {
  var a = 5;
  total = total + a * i;
}

You'll note that the variable a is initialized to 5 each time through the loop. It could be moved out and initialized before the loop, or just converted to a constant in the equation. Again, this is something that an optimizing compiler can do for you. It is probably also something that the better JavaScript engines in the newer browsers will also do for you at some point (not sure if that's true now).

If you've ever had to optimize code by hand, you know there's lots of other tricks that you can apply. The bad thing is that is makes your code unreadable. That's why it's better to let a compiler do it automatically and let your code continue to be both readable and horribly inefficient in it's uncompiled format. Also, a good optimizing compiler will beat the pants off of a human being trying to hand optimize code (that's not the same as coming up with a better algorithm, of course, just that the same algorithm optimized by a compiler will be better).

Anyhow, I hope that gives you a feel for the difference between compressors and compilers and why one can be some much more beneficial than the other.