• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

AOT Compilation

 
Ranch Hand
Posts: 84
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • 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?

 
Rancher
Posts: 379
22
Mac OS X Monad Clojure Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • 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
    Number of slices to send:
    Optional 'thank-you' note:
  • 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
    Rancher
    Posts: 379
    22
    Mac OS X Monad Clojure Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • 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
      Number of slices to send:
      Optional 'thank-you' note:
    • 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
    Rancher
    Posts: 379
    22
    Mac OS X Monad Clojure Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • 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
      Number of slices to send:
      Optional 'thank-you' note:
    • 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
     
    I AM MIGHTY! Especially when I hold this tiny ad:
    a bit of art, as a gift, the permaculture playing cards
    https://gardener-gift.com
    reply
      Bookmark Topic Watch Topic
    • New Topic