开发者

Clojure REPL philosophy and utility applications

Sorry for the long post, but this forum always asks for use cases :-).

I am frequently called upon to write utility applications (GUI and command line) for my organization. I most commonly write these in Java and more recently Scala.

The "philosophy" in Clojure (and other Lisps) seems to center around the REPL, and I have to agree that it makes a nice development environment, but I obviously cannot produce utilities that require that the users "Install Clojure and Clojure-contrib, then unzip the utility into a directory on your hard drive, start Clojure from the command line using the following classpath, ...". The users do not care that the utility is written in Clojure. They just want to point and click or, at most, type "java -jar Utility.jar -?" on the command line.

My question centers around compilation and separating the application into many namespaces/files.

I know tha开发者_JAVA百科t the main method must be in a Clojure file that includes the (gen-class...) command (or the :gen-class clause on the ns command). Do I do the same for the additional Clojure files, or should they be left as a source code that is packed in the JAR and loaded by the main file? How about testing the additional files from the REPL during development?

I have been using leiningen, cake, and maven to build self-contained JARs (containing unpacked clojure.jar, clojure-contrib.jar, and commons-cli.jar files), but so far I have been writing my code in the same file as the main method.


It's up to you whether you AOT-compile your .clj into .class or let Clojure do it dynamically at runtime. In general, I find it's easier during development to avoid AOT and just use AOT as a performance booster for cases where the cost of compiling your .clj on the fly doesn't make sense (limited environments like Google App Engine or utilities where startup time is critical). For server processes that will run for a long time, there is not much advantage in AOT-compiling.

There are a number of complexities around using AOT classes at dev times that are specific to different dev environments.

One down-side of AOT is that your compiled classes might be incompatible with a future version of Clojure and that is more likely than your clj files being incompatible. That may become more important over time.


When it comes to the separation, I'd keep them in separate namespaces/files:

  • One for the :gen-class namespace, containing -main and all the other Java-like things.
  • The other namespace for all the functions.

Ideally, your main should contain just the call to a function from the other namespace, or perhaps some logics for evaluating or repacking of the args.

Your question seems quite similar to the separation between logics code and ui code. You could see the namespace with :gen-class as just an interface provided by your program to Java code, nothing more.


When it comes to the utilities (like command-line, or Swing apps, etc.), there's a trouble with Java in general because of the JVM start time.

Now, you could solve this by making a server app run the REPL in the background all the time, and say, somehow receive an s-expr to be evaluated, and return the result. This could be done as a simple web application which receives an s-expr as URL parameter, and returns the result. Now, with this you could make all utilities in plain old Java, or even bash using wget, since all you'd have to do is access an URL (assuming that server with repl is running in background).

There's a good chance that something like this already exists, so if anyone knows - comments are more than welcome.

Oh, and another thing, the port where repl webapp is exposed would probably have to be closed to the outside world, to prevent Clojure-injections :D

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜