This week's book giveaway is in the Design forum.
We're giving away four copies of Design for the Mind and have Victor S. Yocco on-line!
See this thread for details.
Win a copy of Design for the Mind this week in the Design forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

AOT Compilation

 
Dan King
Ranch Hand
Posts: 84
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 302
10
Clojure Linux Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 84
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
    Posts: 302
    10
    Clojure Linux Mac OS X
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    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
    Posts: 84
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    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
    Posts: 302
    10
    Clojure Linux Mac OS X
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    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
    Posts: 84
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    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
     
    • Post Reply
    • Bookmark Topic Watch Topic
    • New Topic