# Understanding the Restrictions Imposed by the Closure Compiler

The Closure Compiler expects its JavaScript input to conform to a
few restrictions. The higher the level of optimization you ask
the Compiler to perform, the more restrictions the Compiler places
on the input JavaScript.


This document describes the main restrictions for each level of
optimization.
See also [this wiki page](https://github.com/google/closure-compiler/wiki/Compiler-Assumptions)
for additional assumptions made by the compiler.

## Restrictions for all optimization levels

The Compiler places the following two
restrictions on all JavaScript that it processes, for all optimization levels:

- **The Compiler only recognizes ECMAScript.**

  ECMAScript 5 is the version of JavaScript supported almost everywhere.
  However the compiler also supports many of the features in ECMAScript 6.
  The compiler only supports official language features.

  Browser-specific features that conform to the appropriate ECMAScript language
  specification will work fine with the compiler.
  For example, ActiveX objects are created with legal JavaScript syntax, so code
  that creates ActiveX objects works with the compiler.

  The compiler maintainers actively work to support new language versions and
  their features.
  Projects can specify which ECMAScript language version they intend by using the
  `--language_in` flag.
- **The Compiler does not preserve comments.**

  All Compiler optimization levels remove comments, so code that
  relies on specially formatted comments does not work with the
  Compiler.

  For example, because the Compiler does not preserve comments, you
  cannot use JScript's "conditional comments" directly. You can,
  however, work around this restriction by wrapping conditional comments
  in `eval()` expressions. The Compiler can
  process the following code without generating an error:

  ```
   x = eval("/*@cc_on 2+@*/ 0");
  ```

  **Note:** You can include open source licenses and
  other important text at the top of the Compiler output
  using [the @preserve
  annotation.](https://developers.google.com/closure/compiler/docs/js-for-compiler#tag-license)

## Restrictions for SIMPLE_OPTIMIZATIONS

The Simple optimization level renames function parameters, local
variables, and locally defined functions to reduce code size. However,
some JavaScript constructs can break this renaming process.


Avoid the
following constructs and practices when
using `SIMPLE_OPTIMIZATIONS`:

- **`with`:**


  When you use `with` the Compiler can't distinguish
  between a local variable and an object property of the same name,
  and so it renames all instances of the name.


  Furthermore, the `with` statement makes your code harder
  for humans to read. The `with` statement changes the
  normal rules for name resolution, and can make it difficult even for
  the programmer who wrote the code to identify what a name refers to.
- **`eval()`:**


  The Compiler doesn't parse the string argument
  of `eval()`, and so it won't rename any symbols within
  this argument.
- **String representations of function or parameter names:**


  The Compiler renames functions and function parameters but does not
  change any strings in your code that refer to functions or
  parameters by name. You should thus avoid representing function or
  parameter names as strings in your code. For example, the Prototype
  library function `argumentNames()`
  uses `Function.toString()` to retrieve the names of a
  function's parameters. But while `argumentNames()` might
  tempt you to use the names of arguments in your code, Simple mode
  compilation breaks this kind of reference.

## Restrictions for ADVANCED_OPTIMIZATIONS

The `ADVANCED_OPTIMIZATIONS` compilation level performs
the same transformations as `SIMPLE_OPTIMIZATIONS`, and
also adds global renaming of properties, variables, and functions,
dead code elimination, and property flattening. These new passes place
additional restrictions on the input JavaScript. In general, using the
dynamic features of JavaScript will prevent correct static analysis on
your code.

### Implications of global variable, function, and property renaming:


The global renaming of `ADVANCED_OPTIMIZATIONS` makes the
following practices dangerous:

- **Undeclared external references:**

  In order to rename global variables, functions, and properties
  correctly, the Compiler must know about all references to those
  globals. You must tell the Compiler about symbols that are defined
  outside of the code being
  compiled. [Advanced Compilation and
  Externs](https://developers.google.com/closure/compiler/docs/api-tutorial3#mixed) describes how to declare external symbols.
- **Using unexported internal names in external code:**

  Compiled code must export any symbols that uncompiled code refers
  to. [Advanced Compilation and
  Externs](https://developers.google.com/closure/compiler/docs/api-tutorial3#mixed) describes how to export symbols.
-
  **Using string names to refer to object properties:**


  The Compiler renames properties in Advanced mode, but it never renames strings.

  ```
    var x = { renamed_property: 1 };
    var y = x.renamed_property; // This is OK.

    // 'renamed_property' below doesn't exist on x after renaming, so the
    //  following evaluates to false.
    if ( 'renamed_property' in x ) {}; // BAD

    // The following also fails:
    x['renamed_property']; // BAD
  ```

  If you need to refer to a property with a quoted
  string, *always* use a quoted string:

  ```
    var x = { 'unrenamed_property': 1 };
    x['unrenamed_property'];  // This is OK.
    if ( 'unrenamed_property' in x ) {};   // This is OK
  ```
- **Referring to variables as properties of the global object:**

  The Compiler renames properties and variables independently. For
  example, the Compiler treats the following two references
  to `foo` differently, even though they are equivalent:

  ```
    var foo = {};
    window.foo; // BAD
  ```

  This code might compile to:

  ```
    var a = {};
    window.b;
  ```

  If you need to refer to a variable as a property of the global
  object, *always* refer to it that way:

  ```
  window.foo = {}
  window.foo;
  ```

### Implications of dead code elimination


The `ADVANCED_OPTIMIZATIONS` compilation level removes code
that is never executed. This elimination of dead code makes the
following practices dangerous:

- **Calling functions from outside of compiled code:**


  When you compile functions without compiling the code that calls
  those functions, the Compiler assumes that the functions are
  never called and removes them. To avoid unwanted code removal, either:
  - compile all the JavaScript for your application together, or
  - export compiled functions.


  [Advanced Compilation and
  Externs](https://developers.google.com/closure/compiler/docs/api-tutorial3#removal) describes both of these approaches in greater
  detail.

  <br />

- **Retrieving functions through iteration over constructor or
  prototype properties:**


  To determine whether a function is dead code, the Compiler has
  to find all the calls to that function. By iterating over the
  properties of a constructor or its prototype you can find and
  call methods, but the Compiler can't identify the specific
  functions called in this manner.


  For example, the following code causes unintended code removal:

  ```
  function Coordinate() {
  }
  Coordinate.prototype.initX = function() {
    this.x = 0;
  }
  Coordinate.prototype.initY = function() {
    this.y = 0;
  }
  var coord = new Coordinate();
  for (method in Coordinate.prototype) {
    Coordinate.prototype[method].call(coord); // BAD
  }
      
  ```


  The Compiler does not understand that `initX()`
  and `initY()` are called in `for` loop,
  and so it removes both of these methods.


  Note that if you pass a function as a parameter, the
  Compiler *can* find calls to that parameter. For example,
  the Compiler does not remove the `getHello()`
  function when it compiles the following code in Advanced mode.

  ```
  function alertF(f) {
    alert(f());
  }
  function getHello() {
    return 'hello';
  }
  // The Compiler figures out that this call to alertF also calls getHello().
  alertF(getHello); // This is OK.
      
  ```

<br />

### Implications of object property flattening

In Advanced mode the Compiler collapses object properties to
prepare for name shortening. For example, the Compiler transforms this:

```
   var foo = {};
   foo.bar = function (a) { alert(a) };
   foo.bar("hello");
```

into this:

```
   var foo$bar = function (a) { alert(a) };
   foo$bar("hello");
```


This property flattening allows the later renaming pass to rename more
efficiently. The Compiler can replace `foo$bar` with a
single character, for example.


But property flattening also makes the following practices dangerous:

- **Using `this` outside of constructors and
  prototype methods:**


  Property flattening can change meaning of the
  keyword `this` within a function. For example:

  ```
     var foo = {};
     foo.bar = function (a) { this.bad = a; }; // BAD
     foo.bar("hello");
  ```

  becomes:

  ```
     var foo$bar = function (a) { this.bad = a; };
     foo$bar("hello");
  ```

  Before the transformation, the `this`
  within `foo.bar` refers to `foo`. After the
  transformation, `this` refers to the global
  `this`. In cases like this one the Compiler produces this
  warning:

  ```
  "WARNING - dangerous use of this in static method foo.bar"
  ```

  To prevent property flattening from breaking your references
  to `this`, only use `this` within constructors
  and prototype methods. The meaning of `this` is unambiguous
  when you call a constructor with the `new` keyword, or
  within a function that is a property of a `prototype`.
- **Using static methods without knowing which class they're called on:**


  For example, if you have:

  ```
  class A { static create() { return new A(); }};
  class B { static create() { return new B(); }};
  let cls = someCondition ? A : B;
  cls.create();
  ```
  the compiler will collapse both `create` methods (after transpiling from ES6 to ES5) so the `cls.create()` call will fail. You can avoid this with the `@nocollapse` annotation:

  ```
  class A {
    /** @nocollapse */
    static create() {
      return new A();
    }
  }
  class B {
    /** @nocollapse */
    static create() {
      return new A();
    }
  }
  ```
- **Using super in a static method without knowing the superclass:**

  The following code is safe, because the compiler knows that `super.sayHi()` refers to
  `Parent.sayHi()`:

  ```
  class Parent {
    static sayHi() {
      alert('Parent says hi');
    }
  }
  class Child extends Parent {
    static sayHi() {
      super.sayHi();
    }
  }
  Child.sayHi();
  ```

  However, property flattening will break the following code, even if
  `myMixin(Parent).sayHi` is equal to `Parent.sayHi` uncompiled:

  ```
  class Parent {
    static sayHi() {
      alert('Parent says hi');
    }
  }
  class Child extends myMixin(Parent) {
    static sayHi() {
      super.sayHi();
    }
  }
  Child.sayHi();
  ```

  Avoid this breakage with the `/** @nocollapse */` annotation.
- **Using Object.defineProperties or ES6 getter/setters:**

  The compiler does not understand these constructs well. ES6 getter and setters are transformed
  to Object.defineProperties(...) through transpilation. Currently, the compiler is
  unable to statically analyze this construct and assumes properties access and set are side effect
  free. This can have dangerous repercussions. For example:

  ```
  class C {
    static get someProperty() {
      console.log("hello getters!");
    }
  }
  var unused = C.someProperty;
  ```

  Is compiled to:

  ```
  C = function() {};
  Object.defineProperties(C, {a: // Note someProperty is also renamed to 'a'.
    {configurable:!0, enumerable:!0, get:function() {
      console.log("hello world");
      return 1;
  }}});
  ```

  C.someProperty was determined to have no side effects so it was removed.