circular dependency

35 views
Skip to first unread message

Jason Zwolak

unread,
Sep 17, 2015, 10:16:21 AM9/17/15
to clojuresque
I know this problem is not specific to Clojuresque, but it is a common problem in multi-lingual projects.

I have Java code (compiled by "compileJava" in the main configuration) that depends on Clojure code compiled by "compileClojure".  That Clojure code also depends on code from the main configuration.  It seems over kill to separate the code into three configurations since all of the code is part of my project and works together.  If I were just using Java this wouldn't be an issue.

Is there a way to avoid creating a third configuration or source set for the Java code that both the Clojure and Java code depend on?

What's the cleanest way to compile this code?

Meikel Brandmeyer

unread,
Sep 17, 2015, 10:39:12 AM9/17/15
to clojuresque
Sincere there is no tool support for this in Clojure, the only possibility I see is to put things in another source set. Depend clojure on this "early" source set and the rest of Java on Clojure. (I actually have this setup in a groovy project were the code uses some AST transformation which must be compiled up front.)

Another solution (I would actually prefer):
Why would Java code depend on Clojure? The only possibility is generated Interfaces or Classes. But why? I would provide a small Java facade class written in Java which delegates all the calls under the hood to Clojure. Advantage: get rid of AOT (which causes just problems overall) and provide a full and nice Java API including types. The approach is viable and used by Datomic in production.

Example:
https://github.com/lambdanext/javaiscalling

Hope that helps.

Meikel

Jason Zwolak

unread,
Sep 17, 2015, 10:56:56 AM9/17/15
to clojuresque
I like the idea of a Java facade and avoiding AOT (except that means we have source code in our commercially distributed application... that's another problem that we can ignore for some time since the Clojure code isn't exactly revealing much IP).

With gen-class I need to specify the stubs anyway (at least I don't know of any other way to do it) so I can just specify them in the Java facade you mention.

So your proposed solution highlights exactly the situation I'm in (I am currently using AOT to generate classes to call from Java).

For readers that aren't familiar with AOT, it stands for ahead-of-time compilation and is not the default in Clojure.  By default Clojure code is compiled at runtime.  If my code was compiled at runtime then it would have access to all the compiled Java classes I wrote and there would be no problem with circular dependencies.  I chose to use AOT because it seemed to simplify calling Clojure from Java because you could treat the Clojure name space as a class and the functions as static methods without doing anything in Java.  Without AOT, calling Clojure code from Java required more steps and work.  Obviously, this has the problem I mentioned at the beginning of this thread.

Now, I'm going to try without AOT and using Java facades.

Thanks,
Jason

Jason Zwolak

unread,
Sep 17, 2015, 11:07:10 AM9/17/15
to clojuresque
Some more details can be found at http://clojure.org/java_interop under the heading "Calling Clojure from Java" and I would hope this is the authoritative source and will be updated as the language changes.

This link doesn't answer the question of circular dependencies, but given Meikel's proposed solution, this is the way to call Clojure code without having a compile time dependency there by breaking the circular dependency.

Jason Zwolak

unread,
Sep 17, 2015, 2:59:42 PM9/17/15
to clojuresque
Also, there needs to be something like this in the build.gradle file:

compileClojure.dependsOn compileJava

Since my clojure code depends on the java code.  I'm not sure if the above line is the correct way to write this dependency.  It does cause the compileJava task to run, but does it create the necessary dependencies on the .class files so that compileClojure always is run if the class files output by compileJava have changed?

Meikel Brandmeyer

unread,
Sep 18, 2015, 2:14:11 AM9/18/15
to cloju...@googlegroups.com
IIRC, the Right Way(tm) is to register the Java compiler output as input
for the Clojure compile task.

compileClojure {
inputs.files compileJava.outputs
}

Untested, though.

Meikel
Reply all
Reply to author
Forward
0 new messages