Blog Posts tagged with: clojure

Sep 18 2008

Comments

PCL -> Clojure, Chapter 7

This article is part of a series describing a port of the samples from Practical Common Lisp (PCL) to Clojure. You will probably want to read the intro first.

This article covers Chapter 7, Macros: Standard Control Constructs.

Rolling your own

Common Lisp control constructs are generally part of the standard library, not the core language. Ditto for Clojure. If you don't find a control construct you want, you can always roll it yourself. For example, Clojure doesn't have an unless, so here goes:

  (defmacro unless [condition & body]
    `(when (not ~condition)
       ~@body))

defmacro differs from Common Lisp in two important ways.

  • The argument list is a vector [...], not a list (...). (This is true for functions as well, I just hadn't mentioned it yet). Clojure gives vectors, sets, and maps equal billing with lists by giving them their own literal syntax.
  • Clojure uses different reader macros for unquote and unquote-splicing. Where CL uses , and ,@, Clojure uses ~, and ~@.

The avoidance of commas in read macros is a well-considered decision. Commas are whitespace in Clojure. This often results in an interface that is simultaneously human-friendly and list-y. The following two expressions are equivalent:

  {:fn "John" :ln "Doe"}
  {:fn "John", :ln "Doe"}

The latter form makes the map more readable, and more similar to other languages.

doseq

Common Lisp provides dolist for iterating a list. Clojure works in terms of sequences, which are collections that can be traversed in a list-like way. The Clojure analog to dolist is doseq. It can work with lists:

  user=> (doseq [x '(1 2 3)] (println x))
  1
  2
  3

doseq also works with maps. Note the destructuring bind since I care only about the values:

  user=> (doseq [[_ v] {:fn "John" :ln "Doe"}] (println v))
  John
  Doe

In fact, doseq works with any kind of sequence (hence the name). (iterate inc 1) produces an infinite collection incrementing up from 1. (take 5 ...) pulls a finite set of 5 elements from a collection.

  user=> (doseq [x (take 5 (iterate inc 1))] (println x)))
  1
  2
  3
  4
  5

Don't try to doseq an infinite collection, and don't say I didn't warn you.

dotimes

Common Lisp provides dotimes for iteration with counting. Here is the Clojure version of PCL's multiplication table example:

  user=>(dotimes [x 10]
          (dotimes [y 10]
            (print (format "%3d " (* (inc x) (inc y)))))
          (println))
    1   2   3   4   5   6   7   8   9  10 
    2   4   6   8  10  12  14  16  18  20 
    3   6   9  12  15  18  21  24  27  30 
    4   8  12  16  20  24  28  32  36  40 
    5  10  15  20  25  30  35  40  45  50 
    6  12  18  24  30  36  42  48  54  60 
    7  14  21  28  35  42  49  56  63  70 
    8  16  24  32  40  48  56  64  72  80 
    9  18  27  36  45  54  63  72  81  90 
   10  20  30  40  50  60  70  80  90 100 

CL do and loop

Common Lisp provides some more general control constructs: do and loop. Clojure's functions of the same name serve very different purposes. Clojure's do is equivalent to CL's progn, and Clojure's loop works with recur.

You could write Clojure macros to emulate CL's do and loop, but you probably won't want too. Instead, you can use list comprehensions or lazy sequences, which I will introduce later in this series.

Wrapping up

Like CL, Clojure defines control structures using macros. Also like CL, Clojure has control structures that are functional, plus some that are evaluated for their side effects. Clojure's control structures tend to use fewer parentheses.

Clojure does not duplicate CL's general purpose imperative control structures. Instead, you can often use list comprehensions and lazy sequences.


Notes

The sample code is available at http://github.com/stuarthalloway/practical-cl-clojure.

Revision history

Sep 16 2008

Comments

PCL -> Clojure, Chapter 3

This article is part of a series describing a port of the samples from Practical Common Lisp (PCL) to Clojure. You will probably want to read the intro first.

This article covers Chapter 3, Practical: A Simple Database.

Defining a database

The code examples begin with a simple function for creating records. Here is a Clojure approach:

  (defstruct cd :title :artist :rating :ripped)

A cd has four defined slots: title, artist, rating, and ripped. (Note that this is pretty different from the approach taken in PCL. Peter is introducing language features one a time, and hasn't covered structs at this point in the book.)

Next, I need a way to keep an in-memory database of cd information. In PCL, this is done by changing a mutable global. Since Clojure uses immutable data structures, I will take a different approach, and pass the db object (a collection of some kind) to every method.

  (defn add-records [db & cd] (into db cd))

add-records lets us add an arbitrary number of cds to an existing db collection. The use of into allows us to defer the choice of collection type.

I also want an init-db function to populate initial values for the collection. Again I will avoid mutable data and have init-db return the database.

  (defn init-db []
    (add-records #{} 
          (struct cd "Roses" "Kathy Mattea" 7 true)
          (struct cd "Fly" "Dixie Chicks" 8 true)
          (struct cd "Home" "Dixie Chicks" 9 true)))

The #{} is a set literal.

Console output

Next, dump-db can print a summary of the database to the console. Again, since there is no mutable data, I will pass the database to dump-db

  (defn dump-db [db]
    (doseq [cd db]
      (doseq [[key value] cd]
        (print (format "%10s: %s\n" (name key) value)))
      (println)))                               

The calls to doseq are loops: the outer doseq loops over all cds in the db, and the inner one loops over each key/value pair in a cd record. The call to format wraps a Java call to String.format. The output from dump-db looks like this, when called on (init-db):

   title: Roses
  artist: Kathy Mattea
  rating: 7
  ripped: true

   title: Fly
  artist: Dixie Chicks
  rating: 8
  ripped: true

   title: Home
  artist: Dixie Chicks
  rating: 9
  ripped: true        

Console input

Reading in a new record is a little more tricky. I need a generic input function, plus number validation (for the rating field) and yes/no validation (for the ripped field). First, I will write a prompt-read function that displays a prompt and then waits for input:

  (defn prompt-read [prompt]
    (print (format "%s: " prompt))
    (flush)
    (read-line))

Now I can write prompt-for-cd, which will prompt for each of the four fields, and then combine them into a cd:

  (defn prompt-for-cd []
    (struct 
     cd 
     (prompt-read "Title")
     (prompt-read "Artist")
     (parse-integer (prompt-read "Rating"))
     (y-or-n-p "Ripped [y/n]")))

The prompt-for-cd function cannot compile, because it depends on two other functions that I haven't written yet. First, parse-integer:

  (defn parse-integer [str]
    (try (Integer/parseInt str) 
         (catch NumberFormatException nfe 0)))

This function demonstrates two bits of Java interop: the Integer/parseInt syntactic sugar for invoking static methods, and the try/catch special form. The resulting function will coerce any non-numeric input to zero.

Common Lisp has a built-in y-or-n-p for yes/no input, buy Clojure doesn't. So I will write one:

  (defn y-or-n-p [prompt]
    (= "y"
       (loop []
         (or 
            (re-matches #"[yn]" (.toLowerCase (prompt-read prompt)))
            (recur)))))

The call to recur will repeat the loop until the user enters "y" or "n". Since re-matches returns the match, there is no need to capture the input in a local variable.

File load and save

It would be nice to save and reload the database from a file. Since the database is just Clojure data, I can use Clojure's built-in support for serializing objects: pr-str and read-string. Combine these with the beautifully-named spit and slurp, and file I/O is done:

  (use 'clojure.contrib.duck-streams)
  (defn save-db [db filename]
    (spit filename (pr-str db)))

  (defn load-db [filename] 
    (read-string (slurp filename)))

For spit you will need the clojure-contrib library on your classpath.

Querying the database

Now, the fun begins. I would like to have a mini-DSL for querying the database. For example, I might say:

  (filter (artist-selector "Dixie Chicks") (init-db))

This should return all items in the database where the artist is "Dixie Chicks". For this to work, artist-selector needs to be a higher-order function, i.e. a function that returns another function:

  (defn artist-selector [artist]
    #(= (:artist %) artist))

There are two interesting bits of syntactic sugar here.

  • The #(...) creates an anonymous lambda, where % represents the first argument. For example, #(inc %) is the same as (fn [n] (inc n)).
  • The call (:artist %) uses the keyword :artist in function position to look up the corresponding value in %.

A more general query

artist-selector is cool, but it could be much more general. How about a where function that creates a test for any number of criteria? A general form would look like:

  (filter (where {:artist "Dixie Chicks"}) (init-db))

But now I can add multiple criteria. How about all the Dixie Chicks albums that I rated 8?

  (filter (where {:artist "Dixie Chicks" :rating 8}) (init-db))

Here's where:

  (defn where [criteria]
    (fn [m]
      (loop [criteria criteria] 
        (let [[k,v] (first criteria)]
            (or (not k)
                (and (= (k m) v) (recur (rest criteria))))))))

This is a little more complex than artist-selector:

  • The loop processes the criteria, one key/value pair at the time.
  • The let uses a destructuring bind to pull the key and value into k and v.
  • The and joins together multiple criteria.
  • The recur advances to the next criterion.
  • The (or (not k) ... allows the recursion to terminate when no criteria remain.

Notice that the variable name is now m instead of cd. While writing a CD database, I have accidentally produced a completely general purpose where function. Oops. :-)

I wrote the where to explicitly demonstrate implementing sequence operations with recur. You will often find that Clojure has already defined the sequence operation you need. In this case, there where applies its criteria to every object in the sequence. Sure enough, there is an every? that will simplify things:

  (defn simpler-where [criteria]
    (fn [m]
      (every? (fn [[k v]] (= (k m) v)) criteria)))

Updating the database

A nice feature of functional design is composability. We have used where to perform lookup queries with filter, but the same code can be used for update operations. For example, maybe I want to set the rating for all Dixie Chicks albums to 10: clojure (update (some-db) (where {:artist "Dixie Chicks"}) {:rating 10})

update is simply:

  (defn update [db criteria updates]
    (into (empty db) 
     (map (fn [m] 
      (if (criteria m) (merge m updates) m))
    db)))
  • Each cd in the db gets mapped into either itself, or itself+updates, depending on whether the criteria match.
  • The (into (empty db) ... gives back a collection of the same type as db. This will work for out set, but also means that the update function is generalized for other sequence types.

Wrapping up

Look back at where we have been. That's a lot of functionality for several dozen lines of code! The music database now supports

  • console-based input and output
  • file-based persistence
  • generic exact-match queries
  • arbitrary updates to matches

Clojure's unique features helped:

  • The map literal {:key value} made creating the query DSL simple.
  • Java interop was easy and unobtrusive.
  • Immutable programming wasn't so hard, after all. No state mutated in the code above, and yet nothing seemed too alien, did it?

Notes

The sample code is available at http://github.com/stuarthalloway/practical-cl-clojure.

Revision history

  • 2008/09/16: initial version
  • same day! : removed clojure.contrib.string format (format now in Clojure core)
  • 2008/09/17: batch of changes suggested by Rich Hickey. Most of these changes can be summarized as "It doesn't have to be a list!" See the git commit for details.
  • 2008/10/03: added link out to clojure-contrib, based on feedback from Hans Hübner.
  • 2008/10/28: fixed parameter reversal in update example, based on feedback from Chanwoo Yoo.
  • 2008/11/24: updated to the new uniform binding syntax.
  • 2009/10/15: fixed load/save bug by switching to pr-str, based on feedback from Perttu.

Sep 16 2008

Comments

PCL -> Clojure

My current leisure-time project is porting the examples from Peter Seibel's excellent Practical Common Lisp (PCL) to Clojure.

I think Clojure is interesting for three reasons:

  1. Clojure is Lisp, but minus historical baggage.
  2. Clojure gives full access to the JVM and Java libraries.
  3. Clojure groks concurrency and state.

My ground rules are simple:

  • I am not going to port everything, just the code samples that interest me as I re-read Practical Common Lisp.
  • Where Peter introduced Common Lisp features in a planned progression, I plan to use whatever Clojure feature come to mind. So I may jump straight into more "advanced" topics, even in the intro chapters.

Please do not assume that this port is a good introduction to Common Lisp! I am cherry-picking examples that are interesting to me from a Clojure perspective. If you want to learn Common Lisp, read PCL. In fact, you should probably read the relevant chapters in PCL first, no matter what.

The Series

The Book

If you find this series helpful, you might also like my book, Programming Clojure.

Talks

I am available to give conference talks on Clojure. Check the schedule for an event near you, or contact Relevance (info@thinkrelevance.com) to schedule an event.


Notes

Sep 16 2008

Comments

PCL -> Clojure, Chapter 5

This article is part of a series describing a port of the samples from Practical Common Lisp (PCL) to Clojure. You will probably want to read the intro first.

This article covers Chapter 5, Functions.

Passing arguments to functions

One of the cool things about Common Lisp is the variety of ways to pass arguments to functions. You can pass arguments

  • by position or by name
  • as a fixed or variable list
  • with preset defaults for some arguments

Clojure provides many of the same things, but the syntax is different. Here is a function that takes two required arguments, and two optional arguments.

  (defn foo [a b & [c d]]
    (list a b c d))

Here are some examples of calling foo:

  user=> (foo 1 2)
  (1 2 nil nil)

  user=> (foo 1 2 3 4)
  (1 2 3 4)

You can also pass values by name, using a map literal. The function bar expects named arguments a and b. The :or clause specifies a default for b:

  (defn bar [{:keys [a b] :or {b 10}}] (list a b))

Examples of calling bar:

  user=> (bar {:a 1})
  (1 10)

  user=> (bar {:a 1 :b 2})
  (1 2)   

Another nicety is defining an optional parameter's default value in terms of another parameter. Here is a Clojure approach that defaults height to width when creating a rectangle:

  (defn make-rectangle 
    ([width] (make-rectangle width width))
    ([width height] {:width width :height height}))

Usage:

  user=> (make-rectangle 20)
  {:width 20, :height 20}

  user=> (make-rectangle 10 20)
  {:width 10, :height 20}    

Corner cases

Common Lisp also supports discovering whether a user specified a parameter. This comes in handy if you want to detect that the user re-specified the default for some parameter. I didn't find a built-in way to do this in Clojure. Here is one approach:

  (defn which-args-supplied [{:keys [a b c] :as all :or {c 4}}]
    (let [c-supplied (contains? all :c)]
      (list a b c c-supplied)))

The :as :all collects the entire arguments list into all. Then, I use contains? to detect whether the user specified a value for c.

Usage:

  user=> (which-args-supplied {:a 1})
  (1 nil 4 false)

  user=> (which-args-supplied {:a 1 :c 4})
  (1 nil 4 true)

If you wanted to make this feel more like Common Lisp, you could write a macro.

Common Lisp also supports a return-from macro to "return" from the middle of a function. This encourages an imperative style of programming, which Clojure discourages.

However, you can solve the same problems in a different way. Here is the return-from example, rewritten in a functional style so that no return-from is needed:

  (defn pair-with-product-greater-than [n]
    (take 1 (for [i (range 10) j (range 10) :when (> (* i j) n)] [i j])))

Usage:

  user=> (pair-with-product-greater-than 30)
  ([4 8])

  user=> (pair-with-product-greater-than 50)
  ([6 9])

Dynamic invocation

To demonstrate funcall and apply, PCL uses a function to plot a histogram. Clojure provides an equivalent apply. The PCL version of plot also uses CL's loop. Instead, I will use doseq and dotimes for looping:

  (defn plot [f min max step]
    (doseq i (range min max step)
      (dotimes _ (apply f [i]) (print "*"))
      (println)))

The _ is idiomatic for "I don't plan to use this value". In this case I want to do something n times, but the individual iterations do not need to know their ordinal.

With plot in place, we can plot any function of one argument, over any range. (The usefulness of this is sharply limited by the horizontal resolution of your output device). Some examples:

  user=> (plot #(Math/pow % 2) 1 5 1)
  *
  ****
  *********
  ****************

  user=> (plot identity 2 10 2)
  **
  ****
  ******
  ********

Wrapping up

No big surprises here. Function invocation is flexible and powerful in Clojure.


Notes

The sample code is available at http://github.com/stuarthalloway/practical-cl-clojure.

Sep 16 2008

Comments

PCL -> Clojure, Chapter 6

This article is part of a series describing a port of the samples from Practical Common Lisp (PCL) to Clojure. You will probably want to read the intro first.

This article covers Chapter 6, Variables.

Closures (and STM!)

Functions can close over their lexical environment, in both Common Lisp and Clojure. The PCL example for this is the canonical simple counter. You might think you could do something like this in Clojure:

  ; closes over count, but WON'T WORK
  (def counter (let [count 0] #(inc count)))

This poor counter can only count once:

  user=> (counter)
  1

  user=> (counter)
  1

inc returns the increment of counter, but it doesn't change counter. You might look for a setf equivalent in Clojure, but you won't find one. Clojure data structures are immutable.

Of course, we don't really need mutable data here. What we need is a mutable reference to data, that can change to point to a different value later. Clojure provides this via Software Transactional Memory (STM).

Using STM, I can create a ref with ref, and alter a ref with alter. The alter must be inside a transaction, a.k.a. a dosync block.

With all that in mind, here's counter:

  (def counter (let [count (ref 0)] #(dosync (alter count inc))))

This counter actually works. (It is also thread safe).

  user=> (counter)
  1

  user=> (counter)
  2

Nothing stops multiple functions from closing on the same variables. Here is a function that returns an incrementer, decrementer, and accessor, all sharing the same counter:

  (defn counters []
    (let [count (ref 0)]
      (list #(dosync (alter count inc))
              #(dosync (alter count dec))
              #(deref count))))

Note that deref does not require a dosync wrapper.

Creating variables

Common Lisp provides defvar and defparameter to create variables. Between them, these forms provide ways to specify an initial value, documentation string, and init-once semantics.

Clojure's support for these ideas lives partially in clojure.contrib.def. Having used def, I can use defvar to specify an initial value and a documentation string:

  (defvar gap-tolerance 0.0001
    "Tolerance to be allowed in widget gaps")

You can then access the value or the docstring:

  user=> gap-tolerance
  1.0E-4
  user=> (doc gap-tolerance)
  -------------------------
  pcl.chap_06/gap-tolerance
    Tolerance to be allowed in widget gaps

For one-time initialization, you can use init-once:

  (def
   #^{:doc "Count of widgets made so far"}
   widget-count)
  (init-once widget-count 0)

In addition to init-once, the form above also demonstrates an alternate docstring syntax. The #^{...} invokes the metadata reader macro. Here the metadata is a docstring, but the mechanism is general. Clojure also uses metadata for visibility (e.g. private), and for adding type information.

Dynamic Binding

In Common Lisp, you can rebind global (dynamic) variables with let. In Clojure, there is a separate binding macro for this purpose. The following example demonstrates the difference between bind and let in Clojure:

  (defn demo-bindings []
    (let [a "let a" b "let b"]
      (print-a-and-b "let"))
    (binding [a "bound a" b "bound b"]
      (print-a-and-b "binding")))

  (defn print-a-and-b [from]
    (println (format "From %s: [a=%s] [b=%s]" from a b)))

This prints:

    user=> (demo-bindings)
    From let: [a=global a] [b=global b]
    From binding: [a=bound a] [b=bound b]
  • The let creates new lexical bindings for a and b, which shadow the global variables. Inside the let's call to print-a-and-b these local bindings are not in scope.
  • The binding creates new dynamic bindings for a and b. These are thread local, but visible for the entire dynamic scope of the binding, including the call to print-a-and-b.

In Clojure, it is idiomatic to use names like *foo* for variables intended for dynamic rebinding.

Wrapping up

Basic creation and binding of variables in Clojure should make sense to a Common Lisp programmer.


Notes

The sample code is available at http://github.com/stuarthalloway/practical-cl-clojure.

Sep 10 2008

Comments

Java.next #4: Immutability

This is Part Four of a series of articles on Java.next. In Part Four, I will begin to explore how the Java.next languages (JRuby, Groovy, Clojure, and Scala) deal with concurrency. Concurrency is a big topic, so I will subdivide it, narrowing my focus in this part to how the Java.next languages support immutability.

Why concurrency?

Over the last decade, most programmers have written code with little concern for concurrency. Often this has caused problems later, when programs needed to be used in a more concurrent setting. This is only going to get worse: in the future, everything is concurrent.

Why don't programmers do a better job with concurrency? Because it is hard. Read the excellent Java Concurrency in Practice (JCIP), and you will come away impressed with all the clever work that has gone into making Java a good environment for writing concurrent applications. But may also come away thinking "Who is smart enough to get this kind of code right in production?"

Not many people can, and the experts agree that we need an entirely different paradigm for writing concurrent applications. It may even be the case that supporting concurrency is the number one priority for Java.next.

Why immutability?

One of the most difficult things about writing concurrent programs is deciding how to protect mutable shared state. Java provides a locking primitive, synchronized, but locking primitives are difficult to use. You have to worry about

  • data corruption (if you lock too little)
  • deadlock (if you lock too much)
  • performance degradation (even if you get it right)

To make matters worse, it is generally impractical to write automated tests that explore the various possible interleavings of events.

Immutability solves all these problems of locking, by removing the need for ever locking at all. Immutable state can always be shared safely. Nobody can ever see a corrupt value by definition, as values never change.

All of the Java.next languages support immutability to some degree, as I will show below.

Immutability in JRuby

JCIP uses a ThreeStooges class as an extremely simple example for creating immutable objects in Java. Continuing the theme of that example, here is JRuby's immutable stooges:

  require 'set'

  class ThreeStooges
    def initialize(*names)
      @stooges = Set.new(names)
      @stooges.freeze
      self.freeze
    end
    def stooge?(name)
      @stooges.member?(name)
    end
  end

In Ruby, you can set immutability on a per-instance basis, as opposed to a per-class basis. A particular object can become immutable by calling freeze. If the internal components of that object are not primitive, they will need to freeze as well. So, in the constructor above, I freeze the two things at risk of changing: stooges and self.

While immutability is possible in Ruby, be warned. Heavy use of freeze to enable safe concurrency is far from idiomatic.

Immutability in Groovy

In Groovy, the ThreeStooges class looks and works like Java, but prettier:

  class ThreeStooges { 
    private final Set<String> stooges;
    ThreeStooges(String... args) {
      stooges = args as HashSet<String>;
    }
    boolean isStooge(String name) {
      return stooges.contains(name); 
    }
  }

The important details here are that the internal stooges collection is

  • final (cannot be changed after the object is created)
  • private (cannot be accessed outside the object itself)

I could also wrap stooges with unmodifiableSet, but since the ThreeStooges class already wraps stooges without exposing a modifying method, the second wrap is redundant.

Immutability in Scala

In JRuby and Groovy, immutability is possible. In Scala, immutability is preferred. The default collection classes are immutable, so ThreeStooges is just

  class ThreeStooges(names: String*) {
    private val stooges = Set() ++ names
    def isStooge(name: String) = stooges(name)
  }

A few observations here:

  • In Scala, fields must be declared val (immutable) or var (changeable). Scala style encourages you to use val where possible.
  • Scala's Set is immutable.

I find that Scala's inline constructor syntax and braces-free method definition syntax make the Scala definition easier to read than the JRuby or Groovy versions.

Immutability in Clojure

In Clojure, immutability is the default. In fact, everything is immutable, with only two exceptions:

  • calling down into Java APIs (the Clojure version of assembly language)
  • a few data structures which are specifically designed to support Software Transactional Memory (more on this in a later post)

So, the three-stooges can just be a set:

  (defn three-stooges [& names] (set names))
  (defn is-stooge? [name stooges] (stooges name))

A few observations:

  • [& names] is Clojure's varargs syntax.
  • A set can be placed in function position (first item in a list). So (stooges name) can be read as "find name in the set stooges"

Putting immutables to work

To see how immutables can simplify an implementation, consider the Factorizer servlet example from JCIP. The objectives of this example are to

  • calculate the prime factorization of a number
  • cache the most recent factorization
  • use the cached answer where possible, and track the frequency of cache hits
  • track the total number of factorizations

Here is a Java version of the factorizer using synchronized blocks, and stripped down to bare essentials for clarity:

  import java.math.BigInteger;

  public class CachedFactorizer {
      private BigInteger ;
      private BigInteger[] lastFactors;
      private long hits;
      private long cacheHits;

      public void factors(BigInteger i) {
          BigInteger[] factors = null;
          synchronized (this) {
              ++hits;
              if (i.equals(lastNumber)) {
                  ++cacheHits;
                  factors = lastFactors.clone();
              }
          }
          if (factors == null) {
              factors = factor(i);
              synchronized (this) {
                  lastNumber = i;
                  lastFactors = factors.clone();
              }
          }
          return factors;
      }
  }

In order for the CachedFactorizer to be correct and efficient, you need to think carefully about where the synchronized blocks should go. In the example above, there are two synchronized blocks. The first block checks the cache, and updates the counters. It protects:

  • read and write of hits
  • read and write of cacheHits
  • read of lastFactors

The second block updates the cache. It protects:

  • write of lastNumber
  • write of lastFactors

To make sure you understand the approach, ask yourself the following questions:

  • Could the first synchronized block be split into multiple, more granular locks? Would this likely be faster or slower?
  • What about the second block?
  • What operations are unprotected by locks? Is this safe?
  • Would a simple, single-lock approach be correct? Under what circumstances would it perform well?

That's a lot to think about. Now, let's consider the same example, but using immutable data structures.

A Clojure cached-factor

Here is one Clojure approach to cached-factor:

  (def #^AtomicLong hits (AtomicLong. 0))
  (def #^AtomicReference cache (AtomicReference. {:n nil :factors nil}))
  (def #^AtomicLong cache-hits (AtomicLong. 0))

  (defn cached-factor [n]
   (.incrementAndGet hits)
   (let [cached (.get cache)]
     (if (= n (cached :n))
       (do (.incrementAndGet cache-hits)
         (cached :factors))
       (let [factors (factor n)]
         (.set cache {:n n :factors factors})
         factors))))

There are several things to notice here:

  • The hits, cache, and cache-hits take advantage of Java 5's atomic wrapper classes. (The #^ClassName syntax adds type information.)
  • There are no synchronized blocks anywhere.
  • Even though there are no synchronized blocks, you still have to think about the semantics of concurrency. The incrementAndGet method is used to update the two hit counters, and the cache is pulled into a local variable to avoid inconsistent reads.

The real key to this approach, however, is storing a Clojure map in an AtomicReference. Because Clojure data structures are immutable, they can benefit from an AtomicReference in a way that mutable classes cannot.

The immutable approach looks only a little simpler in this small example. But the benefit of using immutable data increases when you compose objects together. If you wanted to compose the synchronized version with another object, you would have have to dig back into the internals of both objects, study their locks, and pick a new lock strategy to cover the two objects together. Composing operations with immutable objects is much easier.

A Scala CachedFactor

Since Scala's default collections are immutable, a Scala approach can closely parallel the Clojure code above:

  class CachedFactorizer {
    case class Cache(val n: Int, val factors: List[Int])
    val hits = new AtomicLong()
    val cache = new AtomicReference[Cache](Cache(2, calculateFactors(2)))
    val cacheHits = new AtomicLong()

    def factor(n: Int) = {
      hits.incrementAndGet
      val cached = cache.get
      if (cached.n == n) {
        cacheHits.incrementAndGet
        cached.factors
      } else {
        val factors = calculateFactors(n)
        cache.set(Cache(n, factors))
        factors
      }
    }

While this is similar to the Clojure approach, the difference is instructive. While the Clojure version stores the cache as a simple Map, the Scala version introduces a strongly-typed Cache class for the cache of values and their factors. The differences here are intended to idiomatic. Either approach could work in either language.

What about the JRuby and Groovy examples?

Could you write the example above in Groovy, JRuby, or even Java? Yes, but it would be non-idiomatic, even ugly. I am not going to show the JRuby and Groovy versions here, because those languages do not offer any concurrency-specific advantages over Java. Scala and Clojure, on the other hand, don't just make immutable objects possible. They make them easy and idiomatic.

Languages are designed to support certain priorities, inevitably at the expense of others. By making immutability a preferred option (Scala) or the standard (Clojure), these languages are encouraging a different paradigm for concurrent applications.

Languages are not about what they make possible, but about what they make beautiful. Clojure and Scala aim to make concurrent programs beautiful, and their preference for immutability is but the tip of the iceberg. In the next installment of this series, I will explore how Clojure and Scala enable concurrent programs through actors, agents, and software transactional memory.


Notes

  • This article is based on the talk Java.next #4: Concurrency . Check the schedule for a talk near you.
  • Thanks to Greg Vaughn and Glenn Vanderburg for their feedback on a draft of this article.
  • Thanks to Rich Hickey for suggesting several Clojure versions of the factorizer example.
  • Feedback on how to improve these examples is most welcome!

Sep 09 2008

Comments

Java.next Presentation #4: Concurrency

Programming concurrency is hard, but the Java.next languages can make things easier. In this talk (Part 4 of the Java.next series), I will demonstrate how to write concurrent applications in Clojure, Groovy, JRuby, and Scala.

Topics will include

  • calling the java.util.concurrent APIs
  • why locks are harmful
  • using immutable objects
  • Scala's actor model
  • Clojure's Software Transactional Memory and Agents

For more information, see the following article on the Relevance blog:

Aug 26 2008

Comments

Java.next Presentation #3: Dispatch

Dispatch takes many forms. Single dispatch, switch statements, pattern matching, and multiple dispatch all meet similar needs: Selecting runtime behavior in response to varying runtime conditions.

Flexible dispatch is a key element of Java.next. All of the Java.next languages support dispatch strategies that are far more flexible than Java's single dispatch.

In this talk (Part 3 of the Java.next series), I will explore how the Java.next languages (Clojure, Groovy, JRuby, and Scala) support dispatch. For more information, see the Java.next Dispatch article on the Relevance blog.

Aug 26 2008

Comments

Java.next #3: Dispatch

This is Part Three of a series of articles on Java.next. In Part Three, I will explore how the Java.next languages (JRuby, Groovy, Clojure, and Scala) support dispatch.

For my purposes here, dispatch is a broad term covering various methods of dynamically choosing behavior: single dispatch, switch/case, pattern matching and multiple dispatch. These concepts are not generally grouped together, but they should be. They are used to solve similar problems, albeit in very different ways.

Single dispatch

Let me start with single dispatch. In Java, methods can be selected based on the type of the object they are invoked on. All the Java.next languages support single dispatch, too:

  ; clojure
  (fly vehicle speed)

  // Java, Groovy, or Scala
  vehicle.fly(speed)            

  # ruby
  vehicle.fly speed

In all of these languages, the actual implementation of fly can vary depending on the run-time type of vehicle. (Clojure also supports multiple dispatch, where the implementation can vary based on the type of speed -- more on that later.)

Better switching

Another way to dynamically choose behavior is with a switch statement. Java has a simple switch statement, based on its historical kinship with C and C++. Switch statements have gotten a bad name, so much so that programmers are encouraged to replace them with polymorphism where possible.

This anti-switching bias is based on the limited kind of switching allowed in languages such as Java. In Java.next, there is a different story. The Java.next languages all have powerful switching capabilities, allowing you to switch on any criteria you like. As an example, consider a method that calculates a letter grade, taking input that is either a number or letter grade.

Ruby's case statement

Here is letter_grade in Ruby:

  def letter_grade(val)
    case val
      when 90..100: 'A'
      when 80...90:  'B'
      when 70...80:  'C'
      when 60...70:  'D'
      when 0...60:   'F'
      when /[ABCDF]/i: val.upcase
      else raise "Not a valid grade: #{val}"
    end
  end

In Ruby, the switch/case variant is called case. The Ruby when clause can take arbitrary expressions. Above you see ranges and regular expressions side-by-side in the same case expression. In general, the when clause expects objects that implement a well-known threequals method, ===. Many Ruby objects have sensible === implementations: ranges match numbers in the range, regular expressions match strings containing the regular expression, classes match instances of the class, etc. But any object can implement ===, so you can implement arbitrarily complex dispatch with Ruby case.

Groovy's switch statement

Here is letterGrade in Groovy:

  def letterGrade(val) {
    switch(val) {
     case 90..100: return 'A'
     case 80..<90:  return 'B'
     case 70..<80:  return 'C'
     case 60..<70:  return 'D'
     case 0..<60:   return 'F'
     case ~"[ABCDFabcdf]": return val.toUpperCase()
      default:  throw new 
                IllegalArgumentException("Invalid grade: $val")
    }
  }

In Groovy, the switch/case variant is called switch. If you compare this code with JRuby, you will see minor syntactic differences:

  • Groovy switch keeps faith with Java, so you have to return or break out
  • Groovy uses default where Ruby uses else.
  • Groovy's top-exclusive range uses ..< whereas Ruby's uses ... .
  • Groovy uses isCase instead of ===. (This is not visible in the code sample, but you would need it to test case matches individually.)

The general ideas are the same. Both JRuby and Groovy provide far more powerful and general approaches than Java's switch.

Clojure's cond function

In clojure, as in many Lisps, you can switch on arbitrary functions using cond. One possible approach to letter-grade would be:

  (defn letter-grade [grade]
    (cond 
     (in grade 90 100) "A"
     (in grade 80 90) "B"
     (in grade 70 80) "C"
     (in grade 60 70) "D"
     (in grade 0 60) "F"
     (re-find #"[ABCDFabcdf]" grade) (.toUpperCase grade)))

In Clojure, regular expressions look like #"...". The in function above is not part of Clojure. I wrote the code the way I wanted it to read, and then wrote this function:

  (defn in [grade low high]
     (and (number? grade) (<= low grade high)))

In Clojure, I probably wouldn't use a regular expression for the letter-matching step, but I wrote the example that way for symmetry with the others.

Clojure's cond is just the tip of the iceberg. Clojure-contrib includes a set of macros for other variants of switch/case, and later in this article I will demonstrate Clojure's multiple dispatch.

Scala's pattern matching

Scala's pattern matching is a powerful generalization of the switch/case idiom in many programming languages. Scala provides out of the box support for pattern matching on

  • constants
  • variables (which can be used in the match result)
  • constructors
  • sequences
  • tuples
  • types

With pattern matching, implementing letterGrade is a snap:

  val VALID_GRADES = Set("A", "B", "C", "D", "F")
  def letterGrade(value: Any) : String = value match {
    case x:Int if (90 to 100).contains(x) => "A"
    case x:Int if (80 to 90).contains(x) => "B"
    case x:Int if (70 to 80).contains(x) => "C"
    case x:Int if (60 to 70).contains(x) => "D"
    case x:Int if (0 to 60).contains(x) => "F"
    case x:String if VALID_GRADES(x.toUpperCase) => x.toUpperCase()
  }

In this implementation, numeric grades and letter grades are both matched first by type. Then, case expressions also allow a guard that limits possible matches to some condition. So, for example, the first case above matches only if value is an Int (type match) and between 90 and 100 (the guard).

Scala's guard expressions are cool, but the combination of type+guard does not exactly parallel the other implementations of letterGrade, which rely on arbitrary predicates in case expressions. Scala can do this too: Scala extractors allow you to create arbitrary patterns. Here is one approach to letterGrade using extractors:

  def letterGrade(value: Any) : String = value match {
    case NumericA(value) => "A"
    case NumericB(value) => "B"
    case NumericC(value) => "C"
    case NumericD(value) => "D"
    case NumericF(value) => "F"
    case LetterGrade(value) => value
  }

Behind the scenes, NumericA and friends are objects that implement an unapply method to determine if and how a value should match the pattern.

A more complex example

Scala's pattern matching is much more general than the letter grade example shows. To see this, check out Daniel Spiewak's series introducing Scala for Java programmers. In Part 4, he gives an example of pattern-matching working in conjunction with case classes, which I will explore below.

Scala's case classes

Case classes offer several interesting properties when compared to regular classes:

  • Case classes automatically get a factory method, e.g. Foo(1) instead of new Foo(1)
  • Case classes automatically get reasonable implementations for toString, hashCode, and equals.

These properties are so useful that Scala programmers use case classes for all kinds of things. But their true purpose is revealed in conjunction with patterns: Case classes work directly with pattern matching, without having to write an extractor as in the previous example.

  class Color(val red:Int, val green:Int, val blue:Int)

  case class Red(r:Int) extends Color(r, 0, 0)
  case class Green(g:Int) extends Color(0, g, 0)
  case class Blue(b:Int) extends Color(0, 0, b)

  def printColor(c:Color) = c match {
    case Red(v) => println("Red: " + v)
    case Green(v) => println("Green: " + v)
    case Blue(v) => println("Blue: " + v)

    case col:Color => {
      print("R: " + col.red + ", ")
      print("G: " + col.green + ", ")
      println("B: " + col.blue)
    }

    case null => println("Invalid color")
  }

The printColor method pattern-matches Red, Green, and Blue to provide special behavior for basic colors. Because these are case classes we can capture the actual color value v. All other colors fall through to a general Color, which prints a more generic message.

Clojure's defmulti

Scala's pattern-matching is a signature feature of the language. How do the other Java.next languages compare? To implement printColor in Clojure, I begin by defining a structure to capture a color:

  (defstruct color :red :green :blue)

Where the Scala example defined basic colors with case classes, in Clojure I can use functions:

  (defn red [v] (struct color v 0 0))
  (defn green [v] (struct color 0 v 0))
  (defn blue [v] (struct color 0 0 v))

Now for the fun part. I will define a multimethod named color-string, which dispatches based on which basic colors are present in the color struct.

  (defmulti color-string basic-colors-in)

basic-colors-in is a dispatch function that reports which colors have nonzero values:

  (defn basic-colors-in [color]
    (for [[k v] color :when (not= v 0)] k))

Now I can define multiple implementations of color-string. The basic syntax is

  (defmethod method-name dispatch-value function-body)

So for the three pure colors, I can define color-string as

  (defmethod color-string [:red] [color] (str "Red: " (:red color)))
  (defmethod color-string [:green] [color] (str "Green: " (:green color)))
  (defmethod color-string [:blue] [color] (str "Blue: " (:blue color)))

I can also provide a catch-all implementation by specifying a dispatch-value of :default:

  (defmethod color-string :default [color] 
    (str "Red: " (:red color) ", Green: " (:green color) ", Blue: " (:blue color)))

Multimethods are more powerful than polymorphic single dispatch in two important ways:

  1. With polymorphic single dispatch, the dispatch function is always the type of the the first argument. With multimethods, the dispatch function can be any arbitrary function, e.g. basic-colors-in above.
  2. With polymorphic single dispatch, polymorphism is limited to the first parameter. The dispatch function for a multimethod can look at all parameters, and vary based on any of them. (This feature is not needed in the color-string example above, but see Runtime Polymorphism for an example.)

Like Scala's pattern matching, Clojure's defmulti provides an extremely powerful and extensible dispatch mechanism.

Accidently blue

Both the Scala and Clojure code above take special action for colors that are declared to be pure blue:

  // Scala
  scala> printColor(Blue(10))          
  Blue: 10
  ; Clojure
  user=> (color-string (blue 10))
  "Blue: 10"

What about colors that are not declared as blue, but are, nevertheless, purely blue. These colors are accidentally blue:

  // different result for accidental blues
  scala> printColor(new Color(0, 0, 10))
  R: 0, G: 0, B: 10
  ; all blues equal
  user=> (color-string (struct color 0 0 10))
  "Blue: 10"

The Scala example was written to dispatch based on type, so it treats accidentally blue colors different from "real" Blues. The Clojure example, on the other hand, dispatches based on the actual color values, so all solid blues are treated the same, no matter how they are created.

Of course, nothing stops me from "fixing" the Scala example, e.g. by dispatching on something other than type:

  case class Color(val red:Int, val green:Int, val blue:Int)

  object ColorDemo {
    def colorString(c:Color) = c match {
      case Color(r,0,0) => "Red: " + r
      case Color(0,g,0) => "Green: " + g
      case Color(0,0,b) => "Blue: " + b

    case col:Color => {
      "R: " + col.red + ", " +
      "G: " + col.green + ", " +
      "B: " + col.blue
    }

    case null => "Invalid color"
      case null => "Invalid color"
    }
  }

Or, I could "break" the Clojure example by adding a type tag, and dispatching on that instead. Rich Hickey posted this example on the Clojure mailing list:

  (defstruct color :red :green :blue)

  (defn color-class [name r g b]
   (assoc (struct color r g b) :tag name))

  (defn red [v] (color-class :red  v 0 0))
  (defn green [v] (color-class :green 0 v 0))
  (defn blue [v] (color-class :blue 0 0 v))
  (defmulti color-string :tag)
  (defmethod color-string :red [c] (str "Red: " (:red c)))
  (defmethod color-string :green [c] (str "Green: " (:green c)))
  (defmethod color-string :blue [c] (str "Blue: " (:blue c)))
  (defmethod color-string :default [{:keys [red green blue]}]
     (str "Color, R: " red ", G: " green ", B: " blue)) 

This version now works like the original Scala version, treating "accidental" blue differently from things marked with a :tag of :blue.

Note that multimethods are open. I can add new colors later without having to modify the existing code:

  (defn orange [r g] (color-class :orange r g 0))
  (defmethod color-string :orange [{:keys [red green]}]
     (str "Orange, R: " red ", G: " green)) 

Dynamic Scala?

If you are a dynamic language programmer fearing the tyranny of the Scala compiler, pattern matching is a cause for rejoicing. With pattern matching, you can bypass static typing and get the flexibility of much more dynamic dispatch. Consider: Scala's pattern matching can be used to dispatch on arbitrary predicates. These predicates are not limited to type relationships known at compile time, so a Scala program that uses pattern matching as the cornerstone of its dispatch strategy can be as dynamic as an extremely dynamic Ruby program. Put another way: Scala's catch-all match default (_) is the moral equivalent of Ruby's method_missing.

Conclusions

Dispatch takes many forms. Single dispatch, switch statements, pattern matching, and multiple dispatch all meet similar needs: Selecting runtime behavior in response to varying runtime conditions.

Flexible dispatch is a key element of Java.next. All of the Java.next languages support dispatch strategies that are far more flexible than Java's single dispatch. These strategies are not perfectly interchangeable, but have a great degree of overlap. For example, Clojure's multimethods and Scala's pattern matching look quite different on the surface but can be used to solve similar problems.

Dispatch can be based on criteria more dynamic than the type system, even in Scala.


Notes

  • This article is based on the JVM Language Shootout talk. Check the schedule for a talk near you.
  • Thanks to Ola Bini, Justin Gehtland, Jason Rudolph, Daniel Spiewak, Venkat Subramaniam, and Greg Vaughn for their feedback on a draft of this article.
  • Thanks to Chouser and Rich Hickey for feedback on the Clojure examples.
  • Feedback on how to improve these examples is most welcome!

Revision History

  • 2008/08/29. Fixed fencepost error in Groovy code (Thanks Scott!). How irritating -- I have working unit tests for all the code and get burned by copy and paste.
  • 2008/08/30. Better Scala pattern match in second example, per Stefan's suggestion.

Aug 12 2008

Comments

Java.next #2: Java Interop

This is Part Two of a series of articles on Java.next. In Part Two, I will look at how Java.next languages interoperate with Java.

Java interop is trivial in all of the Java.next languages. We have Java itself to thank for this--the Java Virtual Machine Specification makes it easy for other languages to reflect against and call Java code.

A Swing example

As a first example, consider calling into the Java Swing API to create an application [1] that has

  • a frame
  • button
  • a button handler that responds with a model dialog

For starters, here is the application in plain old Java:

  //java
  import javax.swing.JFrame;
  import javax.swing.JButton;
  import javax.swing.JOptionPane;
  import java.awt.event.ActionListener;
  import java.awt.event.ActionEvent;

  public class Swing {
    public static void main(String[] args) {
      JFrame frame = new JFrame("Hello Swing");
      JButton button = new JButton("Click Me");

      button.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent event) {
          JOptionPane.showMessageDialog(null,
              String.format("<html>Hello from <b>Java</b><br/>" +
                            "Button %s pressed", event.getActionCommand()));
        }
      });
      frame.getContentPane().add(button);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.pack();
      frame.setVisible(true);
    }
  }

Below, I will present the same Swing application, ported to the Java.next languages. Please take note of two things about these examples:

  • For this post, I am presenting the languages in order of increasing syntactic distance from Java. This makes sense for porting a simple example from the well-known to the increasingly unfamiliar.
  • The ports below are not best practice in the Java.next languages. They are deliberately simplistic, so that I can focus on Java interop. In later installments of this series I will show more idiomatic Java.next code.

Groovy Swing example

Groovy is the Java.next language that looks most like Java. Here is the same example in Groovy:

  //groovy
  import javax.swing.JFrame
  import javax.swing.JButton
  import javax.swing.JOptionPane
  import java.awt.event.ActionListener

  frame = new JFrame("Hello Swing")
  button = new JButton("Click Me")

  button.addActionListener({
    JOptionPane.showMessageDialog(null, """<html>Hello from <b>Groovy</b>
  Button ${it.actionCommand} pressed""")
  } as ActionListener) 
  frame.contentPane.add button

  frame.defaultCloseOperation = JFrame.EXIT_ON_CLOSE
  frame.pack()
  frame.visible = true

If you compare this to the Java example, it is almost the same code, minus a bunch of unnecessary ceremony. The Groovy version lets us omit:

  • semicolons
  • type declarations
  • most parentheses
  • get and set for property access

The most important benefit, however, comes in the action listener. The Groovy version sports

  • a multiline string (delimited by """)
  • string interpolation of it.actionCommand (inside ${})
  • no need to write an anonymous inner class, simply pass an anonymous function

For a more idiomatic approach to Swing in Groovy, see the Groovy SwingBuilder project.

Since this post is about Java interop I will state the obvious: From Groovy, Java interop is entirely trivial.

Scala Swing example

Next, let's look at the Scala version:

  // Scala (almost right, see below)
  import javax.swing._
  import java.awt.event.{ActionEvent, ActionListener}

  object HelloWorld extends JFrame("Hello Swing") {
    def showButtonMessage(msg: String)  =
      JOptionPane.showMessageDialog(null, String.format("""<html>Hello from <b>Scala</b>. Button %s pressed""", Array(msg)));

    def main(args: Array[String]) {
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
      val button = new JButton("Click Me")
      button.addActionListener((e:ActionEvent) => showButtonMessage(e.getActionCommand.toString))
      getContentPane add button
      pack
      setVisible(true)
    }
  }     

The Scala version offers many of the same advantages over Java that the Groovy version provided:

  • fewer type declarations than Java
  • fewer semicolons
  • fewer parentheses

We also see a few items unique to Scala:

  • In Scala, the import wildcard is _, not *. In Scala, * is a valid identifier. (Scala's punctuation-friendly identifiers will be a big advantage later when I am writing DSLs.)
  • Scala has an inline syntax for importing multiple classes in a package.
  • Since we only need one, we declare an object instead of a class.
  • Our object extends JFrame, and Scala lets us call the JFrame constructor inline, instead of having to declare a separate constructor.

Again, the most important differences are in the action listener. Like Groovy, Scala lets us skip the anonymous inner class ritual, and simply pass a function:

  button.addActionListener((e:ActionEvent) => 
    showButtonMessage(e.getActionCommand.toString))

That looks great, except I cheated a little. Scala's implementation of strong typing won't automatically coerce a function into an ActionListener, so the above code won't compile out of the box. Fortunately, Scala's implicit conversions let us have our cake and eat it too: strong typing plus much of the syntactic convenience of a looser type system. All we have to do is tell Scala the the conversion is legal:

  // Yes, we can
  implicit def actionPerformedWrapper(func: (ActionEvent) => Unit) = 
    new ActionListener { def actionPerformed(e:ActionEvent) = func(e) }

With this one-time setup in place, we can now pass a function where an ActionListener is expected.

There seem to be several projects to wrap Swing in more idiomatic Scala. Using one of these libraries you should be able to get a syntax cleaner than the sample code here. See ScalaGUI for one example.

From Scala, Java interop is trivial.

JRuby Swing example

Let's see how JRuby fares:

  include Java
  import javax.swing.JFrame
  import javax.swing.JButton
  import javax.swing.JOptionPane
  import java.awt.event.ActionListener

  button = JButton.new "Click Me"
  button.add_action_listener do |evt|
    JOptionPane.showMessageDialog(nil, <<-END)
  <html>Hello from <b>JRuby</b>.
  Button '#{evt.getActionCommand()}' clicked.
  END
  end

  frame = JFrame.new "Hello Swing"
  frame.content_pane.add button
  frame.default_close_operation = JFrame::EXIT_ON_CLOSE
  frame.pack
  frame.visible = true

If you compare this to the earlier Groovy example, you will see almost exactly the same feature set:

  • fewer type declarations
  • fewer semicolons
  • fewer parentheses
  • simplified property access (no get or set)
  • a multiline string (delimited by END)
  • string interpolation of evt.getActionCommand (the stuff inside #{})

The action listener callback is simplified in a fashion similar to the Groovy example. Ruby automatically generates the ActionListener from a block:

  button.add_action_listener { |evt|
    # do stuff
  }

In the JRuby example I used Ruby conventions for method names, even on Java objects:

  # Ruby
  frame.content_pane

Java programmers expect camel case. As a convenience, JRuby supports both naming conventions:

  # Groovy, Scala, or JRuby
  frame.contentPane

Ruby's flexibility has encouraged a lot of experimentation with alternate syntaxes for Java interop. See JRUBY-903 for some of the history. For a more idiomatic approach to Swing in JRuby, see the Profligacy project.

From JRuby, Java interop is trivial.

Clojure Swing example

Here is the Clojure version:

  ; Clojure 
  ; Clojure
  (import '(javax.swing JFrame JButton JOptionPane))
  (import '(java.awt.event ActionListener))

  (let [frame (JFrame. "Hello Swing")
       button (JButton. "Click Me")]
   (.addActionListener button
     (proxy [ActionListener] []
       (actionPerformed [evt]
         (JOptionPane/showMessageDialog  nil,
            (str "<html>Hello from <b>Clojure</b>. Button "
                 (.getActionCommand evt) " clicked.")))))

   (.. frame getContentPane (add button))
   (doto frame
     (.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
     .pack
     (.setVisible true)))

Because Clojure is a Lisp, the syntax is radically different from the others. This deserves hours of discussion, or none. Since my focus here is on Java interop, I am going to save The Great Parenthesis Debate for a later entry in this series. For now, let us suspend judgment on syntax, and focus exclusively on the Java interop.

Importing Java classes is easy. import takes a list. The first element of the list is a package, and the remaining elements are classes to add to the current namespace. Note that this allows the import of multiple classes in a single line.

  (import '(javax.swing JFrame JButton JOptionPane))

Creating a Java instance is easy. Use the (class. &args) form.

  (JFrame. "Hello Swing")

There are multiple ways to call methods on a Java class. If you want to call a single method, you can use the (.methodName obj &args) form. For static calls, you can also use the (class/method &args) form:

  (JOptionPane/showMessageDialog nil "A message") 

Sometimes you want to chain multiple calls together. Where in Java you would say x.y().z(), in Clojure you can use the (.. x (y) (z)) form.

  (.. frame (getContentPane) (add button))

The last three method calls in our example are all on the same frame object. With Clojure's doto form, you can perform multiple operations on an object without having to repeat the object each time.

  (doto frame
    (setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
    pack
    (setVisible true)))

As with the other examples, the action listener is the most interesting part. In Clojure, proxy will dynamically create a Java instance [2], allowing you to implement interfaces and methods as needed.

  (proxy [ActionListener] []
    (actionPerformed [evt] {do stuff here...}))

As with JRuby, this solution is more general, and requires more syntax, than the Groovy approach. Also as with JRuby, you can easily roll your own syntax.

From Clojure, Java interop is trivial.

Try this at home

The interop story in Java.next is almost boring: It Just Works. So to spice things up a little, here is an exercise in rolling your own constructs, inspired by the examples above. Consider Clojure's import, which can import multiple Java classes in a single line of code.

  (import '(javax.swing JFrame JButton JOptionPane))

Why can't this be even more general? Try your hand at writing a custom import function in one of the Java.next languages. Some useful features might be

  • import all the classes in a JAR
  • import all the classes in the intersection of a package and a JAR
  • import only interfaces
  • import all classes matching some criteria
  • import all classes except those matching some criteria

Let me know what you come up with, and I will link to it here.

Conclusion

In the examples above, I have demonstrated how all of the Java.next libraries can trivially interoperate with Java. Each of examples called the Swing library with fewer lines of code than the Java version. More importantly, the Java.next versions capture the essence of the program with less ceremony.

Seamless interoperation with Java should not be the primary yardstick when measuring Java.next languages, because they all get it right. There are complexities and corner cases beyond what I have shown here, in all of the Java.next languages. But I consider the Java interop problem to be basically solved.

In these first two articles, I have stayed fairly close to Java style while demonstrating Java.next language features. With that groundwork in place, it is time to start using idiomatic Java.next. In the next installment of the Java.next series, we will look at how the Java.next languages support Domain-Specific Languages.


Notes

  • This series is taken from the JVM Language Shootout talk. Check the schedule for a talk near you.
  • Suggestions for improving the code samples above are most welcome.
  • Thanks to Jason Rudolph, Glenn Vanderburg, and Greg Vaughn for reading an earlier draft of this article.

Footnotes

  1. I took the Swing application example from the JRuby samples, and ported it to the other Java.next languages.
  2. Clojure's proxy creates classes as necessary behind the scenes. In Java.next, the dichotomy of class and object is not constantly center stage.

Revisions

  • 2008/08/14. Updated Clojure example and prose per Rich Hickey's suggestion. Updated Groovy example to include pointer to SwingBuilder, per Andres Almiray. Updated JRuby example and prose based on suggestions from Nick Sieger and Ola Bini. Updated Scala example per Tony Morris's suggestion. Thanks for all the improvements!
  • 2009/10/16. Update Clojure example to the modern (dot-requiring) version of doto.

Popular Tags