Problem Statement

In Clojure every expression is a value, however for targets like JavaScript this is not true. JavaScript makes a distinction between expressions and statements. JavaScript dictates where and when expression may appear - the most flexible type of expression is the function expression - it is allowed to appear nearly anywhere. This allows us to write complex tests for if expression - in the compiled JavaScript the test expression will be wrapped in a function that is invoked immediately. While this solves the problem this incurs measurable overhead particularly in critical sections. It is undesirable to provide access to lower level JavaScript boolean operators - it's preferable to allow users to write straightforward code and to optimize this as part of the compilation process.

Originally this was done via the Google Closure Compiler. This worked reasonable well, though Closure could be a bit finicky, immediate function invoke nested to a certain level will not be optimized away, in fact if it's deep enough they'll be left entirely alone. This requires tedious review of the generated JavaScript and manual lifting in the ClojureScript code. While tedious this more or less worked and it was hand optimization that rarely need be applied outside of the most critical sections - Closure would catch most of the cases with simple optimizations (note immediate function invokes not removed by simple optimizations would not be removed with advanced).

Unfortunately the most recent Closure Compiler dependency no longer applies the above optimization slowing down nearly all critical functions that have simple boolean tests involving `and` and `or`. This is because `and` and `or` macroexpand to `let` + `if`.

Possible Solutions

Write a simple AST rewriter for the specific case

Benefits - easy to implement

Tradeoffs

with few improvements to the 2 years old AST design, the cruft is growing and this will only add to it

no other forms that generate immediate called JS functions will be optimized

Design a pluggable pass system

Benefits

force us to make some basic improvements/standardization around the AST

allow any future optimizations to be handled in a modular fashion

no longer depend on Closure Compiler for language optimizations that may be ignored because less applicable to mainstream JS practice