When investigating what the closure compiler does with cljs output, I discovered the following:Google closure does not eliminate unused var reads. This means that e.g. a deftype(deftype A [])which compiles toworkbench.foo.A = (function (){.... snip ....});workbench.foo.A; // <-- because of thisdoes not get stripped out of the compilate if A is never used even with advanced optimizations.What can we do about this? I tried changing clojurescript's deftype macro to not return the type itself.This shrank a clojurescript hello world from about 100k to 75k. Quite an improvement for a single line change.
Is there interest in including hooks for optimizations in CLJS? If so, is the approach outlined above reasonably straightforward or do we need a confluence page?kind regards
Yep I think there are quite a few things like this. But I don't think we need an optimization pass for this paticular case (and I'm not saying that's not a good idea - see below). Hopefully we can a direct patch for this issue around top level deftypes/records.
Definitely needs a Confluence page. I know several people are interested in this. I think it would be pretty sweet to provide common optimizations out of the box.
Certainly, such a simple optimization (omitting var reads in a statement context) could live in the emitter.The next stumbling block to a smaller clojurescript, however, is the global-hierarchy var, which doesn't get removed by the closure compiler. To shake that var, some closed world optimization could be utilized. I'd be happy to work on that, but I need compilation units in order to do that.
I'm aware of this one as well. But again I think we can and should do a quick fix in the compiler for this. Either the user used multimethods or they did not.
These kind of simple approaches may seem "hacky" but I think the benefit to users in terms of code size today outweighs those concerns - the discussed fixes would be quite simple to remove when a more general optimization strategy is in place.
Herwig:I've added you to a couple of groups (clojure-dev and jira-developers) on Confluence that you did not previously belong to. I'm not sure, but this may give you permission to edit Confluence. Let me know if you still cannot do so after receiving this message.
2012/10/16 David Nolen <dnolen...@gmail.com>I'm aware of this one as well. But again I think we can and should do a quick fix in the compiler for this. Either the user used multimethods or they did not.I don't see how such a quick fix could be done, without the compiler gaining a concept of "the whole program", in which the user could have used MMs.In my understanding, the compiler, as it is right now, is fundamentally form-at-a-time, so at the point the global-hierarchy var already gets emitted, you can't possibly know if it will be used.Certainly, you are much more familiar with the implementation, do you see a point where this could already be hacked in?
ClojureScript programmers benefit from the assumption of whole program optimization for production code. Also remember we have analyze-file.
If these weren't true ClojureScript would not be anywhere near as fast as it currently is. Look at all the assumptions we can make when we compile a fn invocation form under advanced compilation.
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
None of the invocation optimizations make any sense for anything other that advanced optimization.
They hard code static assumptions that might get invalidated in any compilation unit other than whole program.
We don't need to look at the whole program at once. Think about why we need declare and most Clojure programs avoid it if they can.
I don't think we need any fancy compiler stuff to fix the two big dead code issues in the near term.
2012/10/16 David Nolen <dnolen...@gmail.com>None of the invocation optimizations make any sense for anything other that advanced optimization.But the invokations in javascript output work even when not using google closure at all, e.g. the REPL.
They hard code static assumptions that might get invalidated in any compilation unit other than whole program.Partially agree: I would call those hard coded static assumptions an ABI (e.g. the naming convention for fixed arity invokations, or the invokation of a protocol fn) and compilation units would only work, when the APIs they consume have a matching ABI (this is true even now, you wouldn't compile parts of your project with different versions of clojurescript, would you?).
We need declare, because clojure features a single pass compiler, and sometimes we want to code mutual recursion without letfn. The moral equivalent for the MM dead code issue would be a compiler flag to turn off multimethods, right?. Certainly doable. If you'd like me to implement that flag before turning to more comprehensive optimization, I'll do it.
Please also note: I'm not proposing to get rid of the single pass semantics of clojure. Quite the opposite. After the analyzer is done with its single pass and has unambigously resolved everything, optimization passes are free to optimize, since the semantics are already established.
But the invokations in javascript output work even when not using google closure at all, e.g. the REPL.Yes because we don't try to optimize them.
Start a CLJS REPL with :static-fns true. Make a function called foo. Call it from a function bar. Redef foo w/ different arities. Now call bar. This will not work. Same if you redef foo to be an instance of a deftype that implements IFn.
We need declare, because clojure features a single pass compiler, and sometimes we want to code mutual recursion without letfn. The moral equivalent for the MM dead code issue would be a compiler flag to turn off multimethods, right?. Certainly doable. If you'd like me to implement that flag before turning to more comprehensive optimization, I'll do it.Either the user used multimethods or they did not. If they did emit the hierarchy. And only bother with this code size optimization during advanced compilation - just always emit the hierarchy otherwise.
Please also note: I'm not proposing to get rid of the single pass semantics of clojure. Quite the opposite. After the analyzer is done with its single pass and has unambigously resolved everything, optimization passes are free to optimize, since the semantics are already established.Nothing I've said has anything do w/ optimization passes. Just how immediate problems could be solved without waiting for that ;)
The emitter still can not look ahead in its single pass, but thinking about it, it seems to me your proposal could be implemented by lazily initializing global-hierachy in derive.
Please also note: I'm not proposing to get rid of the single pass semantics of clojure. Quite the opposite. After the analyzer is done with its single pass and has unambigously resolved everything, optimization passes are free to optimize, since the semantics are already established.Nothing I've said has anything do w/ optimization passes. Just how immediate problems could be solved without waiting for that ;)Ack, I think I'll try the two simple fixes first ;)