Using Clojure Protocols for Java Interop

Clojure's protocols were a feature I'd not used much of until I started working on a little pet project: clj-hector (a library for accessing the Cassandra datastore).

Protocols provide a means for attaching type-based polymorphic functions to types. In that regard they're somewhat similar to Java's interfaces (indeed Java can interoperate with Clojure through the protocol-generated types although it's not something I've tried). Here's the example of their use from the Clojure website:

Protocols go deeper though: they can be used with already defined types (think attaching behaviour through mixing modules into objects with Ruby's include). It's for this reason that they've been a particularly nice abstraction for building adapters upon: glue that translates Java objects to Clojure structures when doing interop.

Here's a snippet from a bit of the code that converts Hector query results into maps:

QueryResultImpl contains results for queries. In one instance, this is RowsImpl which contains Row results (which in turn are converted by other parts of the extend-protocol statement in the real code). The really cool part of this is that dispatch happens polymorphically: there's no need to write code to check types, dispatch (and call recursively down the tree). Instead, you map declaratively by type and build a set of statements about how to convert. Clojure does the rest.

Pretty neat.

2 responses
Hi Paul, I am a developer on the management platform RHQ (http://www.rhq-project.org), and I have explored using Clojure some with RHQ. I quickly found myself taking the same approach as you did to convert the Java types to native Clojure types. I have some reservations about this approach though. First, RHQ is a large code base with lots of complex object graphs. I could provide the mappings on an as-needed basis, but then I have to deal with mixed types which might get confusing. The other issue is the overhead of doing the actual mapping. I was mostly just exploring interop strategies so it wasn't an issue, but it would concern me for production use. What do you feel are the pros/cons to this approach?
I've not done much profiling, but, protocols use Java interfaces so I would imagine that function dispatch is pretty performant (or at least you pay very little in 'dynamic overhead').

However, as for converting an object graph into Clojure types, that's where it may get interesting- in some more complicated cases where you're modifying structures, it's probably a good idea to use Clojure's transients (http://clojure.org/transients). However, using protocols to dynamically walk an object-graph seemed to make using transients a little trickier for me. It was almost certainly me misunderstanding something though.

In short, I think the nicest thing about this approach is that it tidies your adaption code enormously. Compared to writing a function to walk the structure and map stuff imperatively I would prefer protocols all the time. But, with lots of things, I think you'd need to measure it for your case and take a call based on the observed behaviour and numbers.

If it works well enough for production then fantastic.