This week's book giveaway is in the Mac OS forum.
We're giving away four copies of a choice of "Take Control of Upgrading to Yosemite" or "Take Control of Automating Your Mac" and have Joe Kissell on-line!
See this thread for details.
The moose likes Clojure and the fly likes AOT Compilation Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


JavaRanch » Java Forums » Languages » Clojure
Bookmark "AOT Compilation" Watch "AOT Compilation" New topic
Author

AOT Compilation

Dan King
Ranch Hand

Joined: Mar 18, 2009
Posts: 84
I'd like to compile the following Clojure code into a Java class ahead of time. Can anyone explain how to do so?

Sean Corfield
Ranch Hand

Joined: Feb 09, 2011
Posts: 260
    
    5

Simple answer: start here http://clojure.org/compilation

Longer answer:

You need to remember that Java "functions" all have this passed as a first argument so typically when you have String foo(String greeting) { ... } in Java, you're going to have something like (defn -foo ^String [this ^String greeting] ...) in Clojure. -foo tells the Clojure compiler to preserve the function name when generating bytecode.

In your namespace declaration, you'll specify :gen-class to indicate you want the namespace compiled to a Java class.

As an example, here's a log4j appender we wrote at World Singles (with irrelevant bits omitted):

Running lein compile will geneate all the .class files, then lein uberjar will create a standalone JAR (containing the Clojure runtime) which you can deploy like any other JAR file. If you've already added the Clojure JAR to your classpath, you can just use lein jar and deploy the smaller, non-standalone JAR.

FWIW, the above dynamically resolves the save-row function at runtime so we avoid circular loader dependencies (because worldsingles.data.core relies on clojure.tools.logging which needs this AOT class at initialization time). worldsingles.data.core is our mini-ORM which supports CRUD operations on MySQL (via clojure.java.jdbc) and on MongoDB (via CongoMongo) transparently. The elided part of -append also conditionally writes to either :actionLog or :log after some data manipulation. :actionLog and :log represent tables in a MySQL database. :logging is a MongoDB collection off in the cloud. The nice thing about MongoDB is it can store fairly arbitrary Clojure data structures (serialized to BSON - a Binary JSON format) whereas the data structures have to be flattened for MySQL.
Dan King
Ranch Hand

Joined: Mar 18, 2009
Posts: 84
Sean Corfield wrote:Simple answer: start here http://clojure.org/compilation

Longer answer:

You need to remember that Java "functions" all have this passed as a first argument so typically when you have String foo(String greeting) { ... } in Java, you're going to have something like (defn -foo ^String [this ^String greeting] ...) in Clojure. -foo tells the Clojure compiler to preserve the function name when generating bytecode.

In your namespace declaration, you'll specify :gen-class to indicate you want the namespace compiled to a Java class.


So essentially, I need to do the following:
  • Add the :gen-class directive
  • Add "this" as a parameter to each function


  • But why are you adding read-time metadata i.e. (defn -foo ^String [this ^String greeting] ...)?
    Sean Corfield
    Ranch Hand

    Joined: Feb 09, 2011
    Posts: 260
        
        5

    The type hints were meant more as an illustration of where types would go if they were needed, just to show syntax. You'd only need them if you were trying to get rid of reflection warnings. Sorry, probably more confusing than helpful.

    To control the actual generated signatures of methods, you might need :methods on the :gen-class directive, if you don't want default types.
    Dan King
    Ranch Hand

    Joined: Mar 18, 2009
    Posts: 84
    Sean Corfield wrote:The type hints were meant more as an illustration of where types would go if they were needed, just to show syntax. You'd only need them if you were trying to get rid of reflection warnings. Sorry, probably more confusing than helpful.

    To control the actual generated signatures of methods, you might need :methods on the :gen-class directive, if you don't want default types.


    So, if I understand it correctly: the type hints -- ^String -- only deal with reflection warnings, however, in order to control the generated method signature the :methods directive is required. Is there a way to combine both in a singular action?

    Sean Corfield
    Ranch Hand

    Joined: Feb 09, 2011
    Posts: 260
        
        5

    No, because they do completely different things. :methods is purely about the generated method signatures (and if you specify argument types other than Object I don't expect you'll get reflection warnings from operations on the arguments within the function itself). Type hints are used anywhere that you need to eliminate a reflection warning - which is not always arguments. In fact, more often I've seen it in let forms on on actual arguments in a specific Java method call, e.g., (.someCall ^SomeType obj ^String s)
    Dan King
    Ranch Hand

    Joined: Mar 18, 2009
    Posts: 84
    Sean Corfield wrote:No, because they do completely different things. :methods is purely about the generated method signatures (and if you specify argument types other than Object I don't expect you'll get reflection warnings from operations on the arguments within the function itself). Type hints are used anywhere that you need to eliminate a reflection warning - which is not always arguments. In fact, more often I've seen it in let forms on on actual arguments in a specific Java method call, e.g., (.someCall ^SomeType obj ^String s)


    Essentially curious if there was a way to mandate a method signature inline, like type hints, rather than through a "stub."

    Thanks for the explanation.

    Best,
    Dan
     
    I agree. Here's the link: http://aspose.com/file-tools
     
    subject: AOT Compilation