Search code examples
javascriptminifygoogle-closure-compiler

Why does Closure Compiler not shorten this?


I'm not sure whether this is just a bug or an intended feature.

Basically, I have this tiny function (I now see end is colored blue here but this works just fine, if I rename it to something else I still have the issue):

function f(a, b) {
    var start = Math.min(a, b);
    var end = Math.max(a, b);

    tb.selectionStart = start;
    tb.selectionEnd = end;
};

When closure-compiling it, I get:

function f(a,b){var c=Math.max(a,b);tb.selectionStart=Math.min(a,b);tb.selectionEnd=c};

However, why is selectionStart set to Math.min directly, whilst selecitonEnd is set to a variable (c), which is declared first? Isn't it shorter to do tb.selectionEnd=Math.max(a,b)?

Any ideas are appreciated.


Solution

  • EDIT: THERE IS AN "OFFICIAL" ANSWER IN THIS LINK: https://web.archive.org/web/20151226143155/http://code.google.com/p/closure-compiler/issues/detail?id=410

    I think an assignment to a variable, followed immediately by usage of that variable, can be inlined. However, if there is any statement in between that cannot be proven to be free of side-effects, then the compiler won't inline it.

    In your case, assignment to variable "start" is separated from the usage of "start" only by the assignment statement to "end". However, this statement is free of side-effects since Math.max is an internal function and the compiler knows that it is side-effect-free.

    However, in your case, assignment to variable "end" is separated from the usage of that variable by a statement, which is an assignment of "start" to a property. Now, I believe that the compiler does not assume that merely assigning to a property is always side-effect-free; that is because some properties, when assigned, actually cause different behavior, or change global state (such as RegExp). In some systems, property assignments actually trigger certain system-specific features (e.g. hardware interface) that may in-turn contain side-effects.

    That is why, sometimes, when you have code like this:

    foo.bar = 1;
    foo.bar = 2;
    foo.bar = 3;
    

    The compiler won't eliminate the first two statements since assignment to "bar" may have side effects.

    So, in your question, the variable "end" cannot be inlined because the statement tb.selectionStart = start; may have side effects (perhaps only in wierd cases).

    If you make "tb" a local variable, or something that the compiler has complete control of (e.g. a simple object: var tb = {};), then you'll find that the compiler inlines all of the assignments just fine.