JRuby and Clojure - A Good Match?
Clojure is a LISP-style language for the JVM. One focus of Clojure is concurrency, which it supports with its immutable its data structures (Clojure comes with persistent data structures). Another feature is Software Transactional Memory (STM), which allows to use transactions, instead of Locks or Mutexes, to update shared memory. While STM is a controversial technology that still needs to prove itself, having access to an implementation on the JVM offers an easy way to experiment with it.
Clojure is expected to have a 1.0 release in the near future, and a lot of Clojure libraries are already available. Some of them take inspiration from Ruby libraries, just to name a few:
- Compojure is a Clojure web framework which, according to its README, was inspired by the Ruby web framework Sinatra.
- Ring is a way to offer HTTP services, similar to Python's WSGI and Ruby's Rack.
- clj-record is an ActiveRecord-like ORM mapper.
- Lancet is a Clojure build tool, like Rake, by Stuart Halloway
- clj-haml is a port of Ruby's HAML library.
Clojure libraries inspired by Ruby libraries are one way the two languages interact. Another way is JRuby - the two languages share the same underlying runtime, the JVM.
Daniel Kwiecinski explores the idea of combining JRuby and Clojure in a blog entry and experiments with making Clojure data structures and features available in JRuby as Ruby objects.
Particularly interesting in this regard are Clojure's Persistent Data Structures, for instance its Persistent Vectors. Note: In this context, the word "persistent" doesn't refer to data being persisted to disk. Persisted Data Structures are immutable; modifications, like insertions, are possible but they always yield a new "copy" of the full data structure. Clojure's implementation and the immutability constraint allow to avoid having to do a full deep copy; instead, only a relatively small delta has to be copied. Karl Krukow shows the implementation of Clojure's Persistent Vector, and explains how it achieves its performance behavior.
Another opportunity for JRuby developers is Clojure's STM support, which is offers a way for Ruby developers to experiment with this concept. Even if the Ruby code doesn't explcitly use any particular Clojure STM features, it's still possible to write the underlying application model in Clojure, and have JRuby for the fronted part, be it from Rails or other Ruby frameworks.
Another option is to use Clojure for performance bottlenecks. While JRuby's performance is steadily improving, there are still situations where it'd be nice to exchange (J)Ruby's polymorphmism and flexibility for performance. In MRI, performance bottlenecks in a Ruby application can be fixed by writing a native extension. In JRuby, one solution is to write code in Java, be it Java source code or a way to generate JVM bytecode (either bytecode generation with a Ruby bytecode DSL or a language like Charles Nutters' Duby).
Choosing a lower level, system language, be it C (for MRI) or Java (for JRuby) has an obvious downside: dropping down to the level of Java and losing features such as Blocks, many types of metaprogramming, etc.
Clojure is a possible solution for this problem: the language has various levels of flexbility. For instance, normal Clojure functions have low call overhead as they're mostly reduced to static method calls. Clojure does offer different styles of runtime polymorphism, for instance in the form of multimethods.
Clojure is a LISP and comes with a powerful macro system. Macros allow compile time metaprogramming, which brings even more opportunities to offload code generation to the computer (instead of writing boilerplate or repetitive code in Java by hand). Clojure code is always compiled to JVM bytecode, Ahead Of Time (AOT) compilation is also supported. Azul's Cliff Click took a closer look at the performance of some JVM languages, including Clojure and JRuby and provides some information about Clojure's performance. All in all, Clojure offers a lot of opportunities to write fast code in an elegant style.
The other side of the medal is of course a matter of dependencies: using Clojure means another new dependency to a project. Whether it's a good idea to add another, still little known, language like Clojure to a project, is a question every team has to answer.
The STM solution to concurrency and shared data has been widely debated. Clojure creator Rich Hickey had a long discussion with Azul's Cliff Click on the topic of STM. Another source of information about STM is last September's ACMQueue issue on Concurrency.
What do you think: JRuby and Clojure - a good match?
Clojure libraries inspired by Ruby libraries are one way the two languages interact.
You could really say that about any language.
the two languages share the same underlying runtime, the JVM.
Fine, but you can say that about any language that shares a common runtime.
Frankly, I think there's a big problem in the JVM ecosystem as Java (the language) goes into maintenance mode. Clojure is cool, has some great concepts, and Rich Hickey is a really bright guy, but s-expressions are just too weird for your average business IT department. Both JRuby and Clojure are dynamically typed, which is a problem in your average IT department. Plus almost all language research is going in the ML/Haskell like direction.
Boo is coming to the JVM, and despite being pretty obscure on dotnet, and not even out on the JVM yet, it has many powerful features (static/dynamic typing, macros, very readable). I think it's a better fit than either Clojure or JRuby for your average Java developer.
And Boo or Scala may be better fits for the "average" Java developers than any dynamic language, but dynamic languages like JRuby or Clojure or Groovy are the right fit for a lot of problems Java developers struggle with. The JRuby+Clojure mashup is more evidence that the JVM, being a result multi-language VM, allows you to use whatever tools you think fit your problem best. For Daniel, JRuby+Clojure is one such combination of tools.
Tom Gilb & Kai Gilb Jan 26, 2015