Although I basically agree with the Pragmatic Programmers’ old advice about learning a new programming language each year, the time has come for me to slow down.

I have been programming for many years and I know a lot of different languages. Many of them are boring and similar (eg. Java, C#, C++), some are not boring but similar (Ruby, Python) and some are completely different (Clojure, Common Lisp, JavaScript).

I’m well aware that I could learn a lot by studying Haskell or diving deeper into Javascript, but I’m going to take this year off.

Why? Very simple. I still have so much to learn from Clojure. I could write at length about the virtues of functional programming or about how Clojure takes advantage of the JVM. I could go on and on about the REPL, Java libraries, infinite lazy sequences (list of all primes, anyone?), the exceptionally smart community members and so on. But others have already done this much better than I could. For a great introduction to the language itself, go watch the intro videos by Clojure creator Rich Hickey. For all the surrounding stuff, there are lots of interesting blogs to read.

Likewise, although I have a lot of experience with both Ruby and Rails, I’m not done learning here either. Especially, I need to tune my Emacs to achieve better code navigation and debugging support.

Two languages that I really like. This year, I’m going to focus, not diversify.

JRuby/Clojure integration

December 21, 2010

I recently did a demo at an aarhus.rb meeting, showing how to call Clojure code from a Rails app. Specifically, I wanted to try using the very impressive Incanter library which is written in Clojure. This is not just a contrived example – Incanter is something you’d want to integrate with if you needed to do something statistics related.

This post is a walkthrough of how I got a very simple demo app running. It displays a histogram and allows the user to enter the size of the normal distribution sample.

NOTE: The finished Rails app can be found on Github.

1. Set up the basics

As with any other project, I am using RVM for managing multiple (J)Ruby implementations and keeping gemsets project-specific.

So first, create a directory for the Rails app. Inside that directory, create a .rvmrc file containing the following line:

rvm --create jruby-1.5.2@jruby-clojure-demo

Now do a “cd .” to have RVM pick up this file. This switches to jruby-1.5.2 (which must be installed, see RVM docs) and a newly created “jruby-clojure-demo” gemset.

We obviously need Rails for this demo:

gem install rails

This installs Rails 3.0.x as of this writing. Since this takes a little while to complete, fire up another terminal and let’s move on.

2. Fetch all the JARs we need with Leiningen

Leiningen is a build/dependency management tool for Clojure. I’m not using it to build anything for this demo, but it is useful for pulling down all the JARs we need.

Install Leningen, then create a new project with “lein new”, eg. in ~/tmp. Modify the project.clj file to look something like this:

(defproject incanter-test "1.0.0-SNAPSHOT"
  :description "FIXME: write"
  :repositories {"incanter" "http://repo.incanter.org"}
  :dependencies [[org.clojure/clojure "1.1.0"]
                 [org.clojure/clojure-contrib "1.1.0"]
                 [org.incanter/incanter-full "1.0.0"]]
  :dev-dependencies [[swank-clojure "1.2.1"]])

Finally run “lein deps” to have Leiningen download all required JAR files into lib/. This also takes a while, but now our Rails gem is installed and we can move on.

3. Create the Rails app

We use -O to skip activerecord:

rails new . -O

Next, add jrclj to the Gemfile. This is a JRuby/Clojure bridge created by Kyle Burton, and it’s the heart of this integration.

gem 'jrclj'

Do a “bundle install” to install all gems required by our new Rails project.

4. Enabling Clojure integration in the Rails project

To allow us to call Clojure code from the Rails project, we need to load all the JARs we downloaded in step 2.

First, create a “deps” folder inside the Rails app and copy all the JARs into it. Then, insert the following before the Bundler#require call in application.rb:

require 'java' 
Dir["#{File.dirname(__FILE__)}/../deps/*.jar"].each do |jar|
  require jar
end

This code needs to be executed before the Bundler call because the imported JARs are needed for the JRClj bridge to initialize properly.

5. Creating the histogram view

It’s time to call some Clojure code to render our view. I’m not showing how to create the actual Rails controller, the view or the simple form that collects the size attribute. See the Github repo for a working example.

To create the histogram, we use the method incanter.charts/histogram. The input to this method is the result from incanter.stats/sample-normal, and we save its output with incanter.core/save.

The output of incanter.core/save is a stream of PNG data. It should have been possible to simply save this data into a new ByteArrayOutputStream (yes, with JRuby you can just instantiate that class), but because of what looks like a glitch in the JRuby/Clojure bridge, this did not work. It looks like the return types may be wrong in some cases, but I haven’t found time to investigate yet.

So I resorted to a dirty hack: Dropping the PNG data into a file in public/images and simply inserting an image_tag into the view to render it. Thread-safe? I don’t think so :-)

    clj = JRClj.new
    %w{core stats charts}.each { |l| clj._import("incanter.#{l}") }
    clj.eval clj.read_string "(incanter.core/save \
                                (incanter.charts/histogram \
                                   (incanter.stats/sample-normal #{@size.to_i})) \
                                 \"#{::Rails.root.to_s}/public/images/out.png\")"

So what I’m doing here shows one of the two ways you can use JRClj: Evaluating a string containing Clojure code. The clj.eval call above evaluates to the value of the call to incanter.core/save, ie. the outermost sexp in the string.

The other, arguably cleaner and more Ruby-like mode to go, is to instantiate a JRClj object (like above), then call the Clojure functions as if they were Ruby function, with the difference that dashes in method names are replaced with underscores:

jruby-1.5.2 > clj = JRClj.new
=> (truncated...)
jruby-1.5.2 > clj._import("incanter.stats")
=> (truncated...)
jruby-1.5.2 > clj.sample_normal(1000).take(5)  
=> [-1.67885083887929, 0.332869879174951, -0.178234653916897, -0.382876843067349, 1.16325259920326]

Appendix: A Clojure-enabled IRB

I think most Ruby programmers agree that the IRB is a very useful thing, and it becomes even more useful when playing with stuff like JRClj.

Included in the JRClj documentation is a small script that loads the necessary JAR files and fires up an IRB session. I used this while working on the demo, and the script can be found as “jrepl” in the root of the Github repo.

Going to Conj Labs

June 15, 2010

Next week, Karl Krukow and I will be going to Conj Labs in Brussels for three days of intense Clojure hacking. It’s going to be great – I’m really looking forward to it!

I’m sure the actual training will be really good, because I know that both Lau Jensen and Christophe Grand are very competent. But perhaps more importantly, having three days away from work and family will allow me to really concentrate on learning Clojure, including all the surrounding stuff.

I have been reading a lot about the language already, so I hope we’ll be covering all the small things that make Clojure a practical language to use (probably more so than Haskell, Erlang etc.). Project setup, unit testing and so on. These are the kinds of things about a new programming language that require a few days to grasp – to actually get a feel for how it is to use the language on non-trivial projects.

By the way, there are still seats available. Anybody want to join us?

Talking the talk

January 16, 2010

I have come to realize that I talk a lot about Clojure, but I don’t really use it.

I am very excited about functional programming in general and Clojure in particular, so I spend a lot of time catching up on the news on this front. Lots of stuff going on, always.

The other day I sat back for a moment and looked over the hundreds of blog entries piled up in my reading list. Suddenly I realized that most of these would be conveying actual experiences with some language or framework. Be it Ruby, Clojure, Erlang or what have you, these authors have actually tried something out and written about it.

This is more than I can say for myself, unfortunately. I do have several pet projects underway, but I’m not making nearly as much progress as I would like to. Why? Because I spend way too much time reading about new stuff. Reading about what everybody else have been making progress on.

So I have decided that I need to code more and read less. Pretty much the opposite decision from the one I made a few years ago, but hey, times change. It’s a tough balance to strike properly, but I guess we all do the best we can.

Right now I’m splitting my spare time between two areas: Functional programming and dynamic languages. More specifically Clojure and Rails. I have a lot of ideas for projects in both camps, but like I said I’m spending way too much time catching up. I have seriously considered ditching one of these areas completely, but I just can’t do it. Both are extremely interesting from different points of view.

And since I need be both places at once, I must be very careful about how I spend my time. If I want to move forward with my projects, I can’t afford to spend entire evenings reading up on almost a hundred technical blogs. Even worse, almost every single entry is tempting me to go on out on a tangent. So much interesting stuff to learn, so little time. But I’m not really in it for the learning. What I really love about being a geek is the part where I create new stuff. And I think that is what I’m good at, too.

I really need to start walking the walk. It’s OK that I’ll fall a little behind the newsstream, because I’ll gain a much deeper understanding of the areas I choose to focus on. And before long, I should be able to contribute interesting new stuff on my blog as well.

Follow

Get every new post delivered to your Inbox.