I've been looking at getting my startup time down on my Clojure on android
app (it needs to be at least an order of magnitude smaller before I can
ship), and revisited this as a potential candidate. The biggest friction
point was that I would have to change which libraries I use and revisit all
the java interop to make it work nicely as clojurescript.

This got me wondering, would a hybrid approach work? If Rhino can use java
classes, could we rework the clojurescript emitter to emit javascript
corresponding to jvm clojure with rhino's java interop? Presumably if only
the javascript primitives were used and the java objects and interop
retained, the resulting rhino compiled bytecode would be fairly reasonable?
What's more, all the var indirection could be removed and macro
transformations baked in, making it less dynamic and workable for proguard
optimisation even if google's closure compiler didn't work very well with
it.

It's a fairly roundabout approach, and it might be that it would be quicker
to just implement a static production-mode compiler for clojure and skip
the clojurescript hack, but let me know if you think there would be some
mileage in using this to get something working in the short term.

Adam

On Sat Nov 22 2014 at 04:29:47 Sam Beran <sbe...@gmail.com> wrote:

> The code is still half-baked, but in leu of a blog post or code, I can
> summarize my reasoning and approach:
>
>
> *ClojureScript is Designed With UI Responsiveness In Mind*
>
> At present, JVM Clojure is not currently suitable for Android development.
>  Since Android applications are structured around ephemeral Activities,
> any startup penalty over 250 ms is simply unacceptable. Current benchmarks
> [1] are showing 2-5 seconds of startup time, and I have seen no
> straightforward advice on how to achieve an order-of-magnitude increase in
> startup performance. ClojureScript (and JavaScript) is designed from the
> ground up with startup speed in mind. ClojureScript can be used to create
> responsive user interfaces on Android.
>
>
> *Selecting a Host Runtime*
>
> In order to run ClojureScript on Android, I considered the following
> options for host runtimes:
>
>    - *Android WebView * - we can achieve reasonable startup times with a
>    WebView, however any data must be serialized and deserialized in order to
>    communicate between a WebView and Java. Even worse, any long-running object
>    lifecycles must be manually managed, since we cannot rely on garbage
>    collection to maintain object references between the host VM and those of
>    the WebView.
>    - *V8 (JNI) - *I briefly considered compiling a V8 runtime to host
>    ClojureScript. Startup speed would probably outperform the WebView. This
>    would be a lot of work to develop a nice bridging mechanism. Object
>    lifecycle management is better than WebView, but still not ideal. With no
>    C++ or JNI background, I could tell very quickly that this would not be a
>    "weekend project".
>    - *Rhino* - Rhino is a lightweight JavaScript runtime for the JVM.
>    Execution speed is not fast, and since Rhino is not actively maintained, it
>    will probably never support ES6 - not huge concerns for ClojureScript.
>    Since Rhino is a pure-Java runtime, there is very little overhead when
>    communicating between JS<-> Java, and Java GC can be used to maintain
>    object lifecycles.
>    - *Nashorn *- the successor to rhino. Not an option until Android
>    supports InvokeDynamic.[2]
>
>
>
> *Achieving Fast Startup on Rhino*
>
> When I initially ran ClojureScript on Rhino, Startup speed was around 8-10
> seconds - even worse than JVM Clojure! Some quick measurements indicated
> that the bulk of the time was spent with Rhino parsing the JS sources for
> cljs/core.js. I was pleased to discover that Rhino supports bytecode
> precompilation via the jsc utility [3]. I was able to precompile the
> ClojureScript output to bytecode, and achieve *much faster startup -
> around 150ms on device*. This is well within the target performance
> range, and is fast enough to eliminate any noticeable UI lag.
>
> One hurdle I ran into is the 64k method size limit for Java classes. Since
> jsc compiles all .js files to a single method in a Java class, compiling
> cljs/core.js caused errors when compiling to bytecode. I was able to get
> around this by splitting the JS files in half during the build process
> until they were small enough to compile. *I have since implemented some
> optimizations which bring the startup overhead of ClojureScript down to <
> 100 ms.*
>
>
> *Pure ClojureScript Android Applications*
>
> Since I am precompiling the ClojureScript sources, I can also generate
> Java classes using ClojureScript macros. Here is an example of an Android
> Activity written in ClojureScript. This activity is compiled to Java in a
> similar manner to Clojure's gen-class mechanism:
>
> (ns cljs-hello.core
>     (:require-macros [lambdroid.compile :refer [java-class]]))
>
> (java-class
>     {:name "io.lambdroid.MyActivity"
>      :extends android.app.Activity})
>
> (defn ^:override onCreate [this ^android.os.Bundle state]
>   (.onCreate this state)
>   (.setContentView this io.lambdroid.R.layout/activity_hello_world)
>   (.setText (.findViewById this io.lambdroid.R.id/message
> <http://io.lambdroid.r.id/message>)
>     "Hello From ClojureScript"))
>
>
> Note that this generated activity class is created by Android directly and
> has full access to Android asset bundles, so users of this library *will
> not need to write any Java whatsoever* .
>
>
> *Next Steps*
>
> There are a few things I still need to do before releasing code:
>
>
>    - Extract build logic into Gradle plugin - it is currently just some
>    build scripts in an example app.
>    - Build an Android REPL that can run in the context of the current
>    activity
>    - Incremental builds (cljs compile time is currently slow)
>
>
> Once these are finished, I plan to release Lambdroid under a permissive
> license.
>
>
> *ClojureScript JVM Applications?*
>
> As Uday and Mike have alluded, this appriach could potentially be used to
> run applications on the JVM as well. This would be ideal for CLI
> applications and development. However, due to the many differences between
> CLJS and Clojure[4], I think this might be difficult to write the necessary
> shims to get something like Leiningen running on Clojurescript. Also, I
> think Nashorn would be a more suitable runtime for JVM applications. I’d
> love to have someone with more experience weigh in on this possibility!
>
> Cheers,
> Sam
>
> [1]
> http://nicholaskariniemi.github.io/2014/03/12/clojure-android-startup-benchmarks.html
> [2]
> http://mail.openjdk.java.net/pipermail/nashorn-dev/2013-January/000240.html
> [3]
> https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino/JavaScript_Compiler
> [4] https://github.com/clojure/clojurescript/wiki/Differences-from-Clojure
>
>
>  --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clojure+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to