Blog Posts tagged with: clojure

Feb 18 2013

Comments

Hash Maps as Mini State Machines

While working with Ryan Neufeld last Friday, we came across a problem that I had experienced more than once in my programming career: how to toggle a hash map value between two (or more) states.

As a starting example, let's assume that we have a hash map that contains a single key/value, and that we want to toggle the value between -1 and 1. We could write the function thusly:

(defn toggle-value [m]
  (update-in m [:value]
    (fn [v]
      (if (>= v 0)
        -1
        1))))

Now while this code will work, it's not exactly elegant, nor concise. And if we had more than two states (-1, and 1) then we would be forced to change the "if" into a "case" (or a "cond") and then add more and more state transitions to the "if" expression, and our already ugly code would get that much uglier.

It was at this part of my pairing session with Ryan that I remembered an old trick from when I first learned to program in QBasic (more than a few years ago). The trick was that multiplying either -1 or +1 by -1 will cause the resulting value to "toggle" between the two numbers. Actually this works for any states that need to toggle between -N and N, but we'll use -1 today to demonstrate:

(defn toggle-value [m]
  (update-in m [:value] (partial * -1)))

This code is much more concise, but perhaps not as clear. However, for the problem Ryan and I were dealing with on Friday, we couldn't use numbers: we needed to use keywords. We had two states: ":checked" and ":unchecked" and possibly nil. We needed a clear, concise way to toggle between these three states, without writing an ugly case/cond block. In my mind I thought, "we need a function that will return a new state, given an old state. A function that takes a single arg, and returns the new state value." And then I remembered: "Clojure hash maps are functions! And they take a single value (key) and return a single result (value)." Well then, we can write our state transitions with this little bit of code:

(def toggle-states
  {:checked :unchecked
   :unchecked :checked
   nil :checked})

(defn toggle-value [m]
  (update-in m [:value] toggle-states))

This is what I consider good Clojure code. It's simple, clean, concise, and easily extensible. And hopefully it comes in as handy for you as it did for me.

Jan 14 2013

Comments

Taming side-effects with mutability

Clojure prefers immutable values and referentially transparent functions. But it also works well with the Java ecosystem, where everything is an object... mostly mutable.

I was recently dealing with ASM, the bytecode manipulation library. Most of the API is based on the Visitor pattern. To read a class from bytecode, you construct a ClassReader object from an array of bytes or an input stream, then tell it to accept an object that implements the ClassVisitor interface:

public interface ClassVisitor{
  void visit(int version, int access, String name, String signature, 
      String superName, String[] interfaces);
  void visitSource(String source, String debug);
  void visitOuterClass(String owner, String name, String desc);
  AnnotationVisitor visitAnnotation(String desc, boolean visible);
  void visitAttribute(Attribute attr);
  void visitInnerClass(String name, String outerName, 
      String innerName, int access);
  FieldVisitor visitField(int access, String name, String desc, 
      String signature, Object value);
  MethodVisitor visitMethod(int access, String name, String desc, 
      String signature, String[] exceptions);
  void visitEnd();
}

Well, now we see a bit of a problem. The ClassReader gets to call these methods, which mostly return void. When a ClassVisitor does return an object, it returns yet another visitor that the ClassReader calls to descend into members of the class. The methods of the visitor get access to information about the class, but how do we get it out?

In other words, how do you use an API that is 100% about side-effects and mutability inside a language that favors immutable values and pure functions?

One solution is to use mutability to contain the side-effects within a function, such that the function is referentially transparent from the outside. In so doing, we tame the side-effects and put a boundary around them:

(defn analyze [c]
  (let [classinfo (atom {})
        v         (reify ClassVisitor
                    (visit [this version access name sig supername interfaces]
                      (swap! classinfo assoc 
                             :static?    (static? access)
                             :interface? (interface? access)
                             :final?     (final? access)
                             :classname  name 
                             :super      supername))
                    (visitSource [this source debug])
                    (visitOuterClass [this owner name desc])
                    (visitAnnotation [this desc visible])
                    (visitAttribute [this attr])
                    (visitInnerClass [this name outername innername access])
                    (visitField [this access name desc sig value]
                      (swap! classinfo update-in [:members] conj 
                             {:type       :field
                              :visibility (visibility access)
                              :static?    (static? access)
                              :final?     (final? access)
                              :name       name})
                      nil)
                    (visitMethod [this access name desc sig exceptions]
                      (swap! classinfo update-in [:members] conj 
                             {:type       :method
                              :visibility (visibility access)
                              :static?    (static? access)
                              :final?     (final? access)
                              :abstract?  (abstract? access)
                              :name       name})
                      nil)
                    (visitEnd [this]))]
    (.accept c v 0)
    @classinfo))

In the let form at the beginning, I create a new atom that holds an empty map. This will be my mutable state for this function. Then I create an instance of ClassVisitor, where most of the methods do nothing and return nil. Only visitClass, visitField, and visitMethod are interesting to me. In those, I mutate the atom to attach the info that ClassReader passed to the visitor.

After the setup in the let, all that is left is to call ClassReader.accept with the new visitor. At that point the ClassReader does its bytecode interpretation and makes all its calls into the visitor. Finally, I get the resulting value out of the classinfo atom, which now has a nice, immutable Clojure-friendly map of information collected from that class file.

This technique is similar to using transients to build collections: allow mutability within a function, but don't let it escape. Transients do it for speed. The ClassVisitor does it to bridge to an object-oriented API.

Oct 16 2012

Comments

Introducing Word Magic

You might have noticed that we have a number of authors at Relevance. Some of us studied literature and linguistics. We are a wordy bunch. We're also kind of obsessed with time, so it's shouldn't be a surprise that we would be interested in how language evolves over time. Lucky for us, then, that Google has digitized every book they can get their scanners on and made that data available to the world.

Read More »

Jul 31 2012

Comments

Rich Hickey - Podcast Episode 014

cover art

I recently found myself in Durham at the same time as Rich Hickey. Obviously, Rich has quite a few major accomplishments under his belt, including creating Clojure, ClojureScript, and Datomic, three technologies I personally use and love. Understandably, I think, I've wanted to have him on the podcast since the show started.

As it happens, Rich is also a super nice guy, and was therefore kind enough to sit down for a few minutes and indulge me. I really enjoyed our conversation about Clojure, music, Datomic, the fascinating question of whether our ears have a "focus" mechanism, how to design things by taking them apart, and a variety of other topics. I'm sure you'll enjoy listening to this episode as much as I enjoyed recording it!

Download the episode here.

Read More »

Apr 26 2012

Comments

ThinkRelevance: The Podcast - Episode 010 - Stu Halloway

cover art

One of the hardest things about working at Relevance over the last couple of years has been keeping quiet about Datomic. So when we heard that Datomic was being released, I immediately sent an email to Stuart Halloway asking if he'd be willing to do a podcast episode, not just because he had such a big hand in Datomic, but because as one of the founders of Relevance and as an all-around interesting guy I knew it would make for a great show.

I don't think I was wrong. So have a listen as we talk about Datomic, simulation testing, a capella music, and what makes Stu want to drop-kick a gorilla, and see if you agree. Thanks for listening!

Download the episode here.

Read More »

Mar 28 2012

Comments

ThinkRelevance: The Podcast - Episode 008 - Michael Fogus

cover art

Anyone who's been around Clojure for a little while will have heard the name Michael Fogus, who is our guest on this episode of the podcast. Fogus (as we call him) is a hacker, author, and all-around nice guy. He has recently launched Himera, a web service that compiles ClojureScript to Javascript. I've wanted to interview Fogus for quite a while, and that was all the excuse I needed.

While we were talking, we touched not only on Himera, but on pair programming, Datomic, music, and a bunch of other stuff. I hope you enjoy listening to this episode as much as I enjoyed recording it!

Download the episode here.

Read More »

Jul 10 2011

Comments

Heroku-ification of a Clojure App

Here at Relevance, Inc we often use Heroku for our Rails apps. Unfortunately, there hasn't been a similarly easy deployment story for our Clojure web apps. Recently, Heroku has changed that with their Cedar stack.

My colleague, Craig Andera, has been working on a web port of a board game called Artifact. I noticed he added a GitHub Issue "Deploy app to Heroku" This seemed like the perfect time to show off just how easy it is to deploy a Clojure web app to Heroku.

I grabbed a recent commit that was configured to run a local Jetty server. Here is the simple process I followed to get his app deployed to Heroku. As a prerequisite, you should have a Heroku account as well as the heroku gem installed. That process is described on their site.

Start with cloning the repo

git clone git@github.com:candera/artifact.git
cd artifact

The next step is to create a new heroku app on cedar called artifact. When this command is run from inside your app, the remote heroku repository is automatically added for you.

heroku create --stack cedar artifact

Then modify the -main function to work with how Heroku manages ports. The change we are making here is to read the port from the environment variable when it is available.

In core.clj, change the following block of code from

(defn -main [& args]
  (run-jetty app {:port 8080}))

to

(defn -main [& args]
  (let [port (Integer/parseInt (get (System/getenv) "PORT" "8080"))]
    (run-jetty app {:port port})))

Next, create a Procfile in the root dir of the app to tell Heroku how to start our app. This tells the web dyno to use leiningen to launch the web server.

web: lein run -m artifact.core

Commit the changes and push to Heroku.

git add .
git commit -m "Heroku-ify"
git push heroku master

And finally view the page.

heroku open

You can see the app at http://artifact.herokuapp.com. It is still in early development, so expect to run into rough edges. If you'd like to help, I'm sure Craig would love your contributions.

The process of taking a working Clojure web app and moving it to Heroku took me less than ten minutes, a small code change, and an additional line of config. This is a major development in the life of Clojure web development. With Heroku, we can build an app with the power of Clojure and the ease of deployment that Heroku provides to other frameworks, such as Rails. This helps us continue to expand our business and offer choice in deployment strategies to all our customers.

For more detail than just this simple intro, be sure to read "Building a Database-Backed Clojure Web Application".

Oct 19 2009

Comments

The Case for Clojure

The case for Clojure is richly detailed and well-documented. But sometimes you just want the elevator pitch. OK, but I hope your building has four elevators:

  • "Concurrency is not the problem! State is the problem. Clojure's sweet spot is any application that has state."
  • "Don't burn your legacy code! Clojure is a better Java than Java."
  • "Imperative programming and gratuitous complexity go hand in hand. Write functional Clojure and get shit done."
  • "Design Patterns are a disease, and Clojure is the cure."

Any one of these ideas would justify giving Clojure a serious look. The four together are a perfect storm. Over the next few months I will be touring the United States and Europe to expand on each of these themes:

  • "e;Clojure's sweet spot is any application that has state."e; At Oredev, I will be speaking on Clojure and Clojure concurrency. I will demonstrate how Clojure's functional style simplifies code, and how mere mortals can use Clojure's elegant concurrency support.
  • "Clojure is a better Java than Java." I will be speaking on Clojure and other Java.next languages at NFJS in Atlanta and Reston.
  • "Design Patterns are a disease, and Clojure is the cure." I will sing a siren song of Clojure to my Ruby brethren at RubyConf.
  • "Write functional Clojure and get shit done." At QCon, I will give an experience report on Clojure in commercial development. Our results so far: green across the board. Both Relevance and our clients have been pleased with Clojure.

Want to learn about all four of these ideas, and more? Early in 2010, I will be co-teaching the Pragmatic Studio: Clojure with some fellow named Rich Hickey.

If you can't make it to any of the events listed above, at least you can follow along with the slides and code. All of my Clojure slides are Creative-Commons licensed, and you can follow their development on Github. Likewise, all the sample code is released under open-source licenses, including

And remember: think globally, but act only through the unified update model.

Oct 07 2009

Comments

Brian's Functional Brain, Take 1.5

Last week, Lau wrote two excellent sample apps (and blog posts) demonstrating Brian's Brain in Clojure. Continuing with the first version of that example, I am going to demonstrate

  • using different data structures
  • visual unit tests
  • JMX integration (gratuitous!)
  • an approach to Clojure source code organization

Make sure you read through Lau's original post first, and understand the code there.

Data Structures

In a functional language like Clojure, it is easy to experiment with using different structures to represent the same data. Rather than being hidden in a rat's nest of mutable object relationships, your data is right in front of you in simple persistent data structures. In Lau's implementation, the board is represented by a list of lists, like so:

  (([:on 0 0] [:off 0 1] [:on 0 2]) 
   ([:on 1 0] [:on 1 1] [:off 1 2]))

Each cell in the list knows its state (:on, :off, or :dying), and its x and y coordinates on the board. The board data structure is used for two purposes:

  • the step function applies the rules of the automaton, returning the board's next state
  • the render function draws the board on a Swing panel

These two functions have slightly different needs: the step function cares only about the state of adjacent cells, and can ignore the coordinates, while the render function needs both.

How hard would it be to convert the data to a form that stores only the state? Not hard at all:

  (defn without-coords [board]
    (for [row board]
      (for [[state] row] state)))

You could write without-coords as a one-liner using map, but I prefer how the nested fors visually call out the fact that you are manipulating two dimentional data.

Without the coords, the board is easier to read:

  ((:on :off :on)) 
   (:on :on :off))

If you choose to store the board this way, you will need to get the coordinates back for rendering. That's easy too, again using nested fors to demonstrate that you are transforming two-dimensional data:

  (defn with-coords [board]
    (for [[row-idx row] (indexed board)]
      (for [[col-idx val] (indexed row)]
           [val row-idx col-idx])))

So, with a couple of tiny functions, you can easily convert between two different representations of the data. Why not use both formats, picking the right one for each function's needs?

When performance is critical, there is another advantage to using different data formats: caching. Consider the step function, which uses the rules function to determine the next value of each cell:

  (defn rules
    [above [_ cell _ :as row] below]
    (cond
     (= :on    cell)                              :dying
     (= :dying cell)                              :off  
     (= 2 (active-neighbors above row below))     :on   
     :else                                        :off  ))

The "without coordinates" format used by step and rules passes only exactly the data needed. As a result, the universe of legal inputs to rules is small enough to fit in a small cache in memory. And in-memory caching is trivial in Clojure, simply call memoize on a function. (It turns out that for this particular example, the calculation is simple enough that memoize won't buy you anything. Lau's second post demonstrates more useful optimizations: transients and double-buffering. But in some problems a cacheable function result is a performance lifesaver.)

If you use comprehensions such as Clojure's for to convert inputs to exactly the data a function needs, your functions will be simpler to read and write. This "caller makes right" approach is not always appropriate. When it is appropriate, it is far less tedious to implement than the related adapter pattern from OO programming.

Since multiple data formats are so easy, you can use yet another format for testing.

Testing

Brian's Brain is a simulation in two dimensions, it would be nice to write tests with a literal, visual, 2-d representation. In other words:

  ; this sucks
  (is (= :on (rules (cell-with-two-active-neighbors))))

  ; this rocks
  O..
  ...  => O     
  ..O

In the literal form above the O is an :on cell, and the . is an :off cell.

Creating this representation is easy. The board->str function converts a board to a compact string form:

  (defn board->str
    "Convert from board form to string form:

     O.O         [[ :on     :off  :on    ]
     |.|     ==   [ :dying  :off  :dying ]
     O.O          [ :on     :off  :on    ]]
  "
    [board]
    (str-join "\n" (map (partial str-join "") (board->chars board))))

The board->chars helper is equally simple:

  (def state->char {:on \O, :dying \|, :off \.})
  (defn board->chars
    [board]
    (map (partial map state->char) board))

With the new stringified board format, you can trivially write tests like this:

  (deftest test-rules
    (are [result boardstr] (= result (apply rules (str->board boardstr)))
         :dying  "...
                  .O.
                  ..."

         :off    "O.O
                  ...
                  O.O"

         :on     "|||
                  O.O
                  |||"))

The are macro makes it simple to run the same tests over multiple inputs, and with liberal use of whitespace the tests line up visually. It isn't perfect, but I think it is good enough.

One last note: the string format used in tests is basically ASCII art, so you can have a console based GUI almost for free:

  (defn launch-console []
    (doseq [board (iterate step (new-board))]
      (println (board->str board))))

JMX Integration

Ok, JMX integration is gratuitous for an example like this. But clojure.contrib.jmx is so easy to use I couldn't resist. You can store the total number of iterations performed in a thread-safe Clojure atom:

  (def status (atom {:iterations 0}))

Then, just expose the atom as a JMX mbean.

  (defn register-status-mbean []
    (jmx/register-mbean (Bean. status) "lau.brians-brain:name=Automaton"))

Yes, it is that easy. Create any Clojure reference type, point it at a map, and register a bean. You can now access the iteration counter from a JMX client such as the jconsole application that ships with the JDK.

To make the mbean report real data, wrap the automaton's iterations in an update-stage helper function that both does the work, and updates the counter.

  (defn update-stage
    "Update the automaton (and associated metrics)."
    [stage]
    (swap! stage step)
    (swap! status update-in [:iterations] inc))

If you haven't seen update-in (and its cousins get-in and assoc-in) before, go and study them for a moment now. They make working with non-trivial data structures a joy.

You might disagree with my choice of atoms. With a pair of references, you could keep the iteration count exactly coordinated with the simulator. Or, with a reference plus an agent you push the work of updating the iteration count out of the main loop. Whatever you choose, Clojure makes it easy to both (a) implement state and (b) keep the statefulness separate from the bulk of your code.

Source Code Organization

Lau's original code weighed in at a trim 67 lines. Now that the app supports three different data formats, a console UI, and JMX integration, it is up to around 150 lines. How should we organize such a monster of an app? Two obvious choices are:

  • put everything in one file and one namespace
  • split out namespaces by functional area, e.g. automaton, swing gui, and console gui

I don't love either approach. The single file approach is confusing for the reader, because there are multiple different things going on. The multiple namespace approach is a pain for callers, because they get weighed down under a bunch of namespaces to do a single thing.

A third option is immigrate. With immigrate you can organize your code into multiple namespaces for the benefit of readers, and then immigrate them all into a blanket namespace for casual users of the API. But immigrate may be too cute for their own good.

Instead, I chose to use one namespace for the convenience of callers, and mutilple files to provide sub-namespace organization for readers of code. I mimiced the structure Tom Faulhaber used in clojure-contrib's pprint library: a top level file that calls load on several files in a subdirectory of the same name (minus the .clj extension):

  lau/brians_brain.clj  
  lau/brians_brain/automaton.clj
  lau/brians_brain/board.clj
  lau/brians_brain/console_gui.clj
  lau/brians_brain/swing_gui.clj

I also used this layout for clojure-contrib's JMX library.

Parting Shots

Over the course of Lau's two exampples and this one, you have seen:

  • an initial working application in under 100 lines of code
  • transforming data structures for performance optimization
  • transforming data structures for readability
  • a second (console) gui
  • optimizing the Swing gui with double buffering
  • optimizing with transients
  • visual tests
  • easy addition of monitoring with JMX

And here are some things you haven't seen:

  • classes
  • interfaces
  • uncontrolled mutation
  • broken concurrency

Would it be possible to write a threadsafe Brian's Brain using mutable OO? Of course. Is there a benefit to doing so? I would love to hear your thoughts on the subject, especially in the form of code.

Further Reading

Aug 12 2009

Comments

Rifle-Oriented Programming with Clojure

Any comparison of hot JVM languages is likely to note that “Clojure is not object-oriented.” This is true, but it may lead you to the wrong conclusions. It’s a little like saying that a rifle is not arrow-oriented. In this article, you will see some of the ways that Clojure addresses the key concerns of OO: encapsulation, polymorphism, and inheritance.

This is a whirlwind tour, and we won't have time to cover the full details of all the Clojure code you will see. When we are done, I hope you will decide to explore for yourself. You can download and start using Clojure by following the instructions on the getting started page.

Just Enough Clojure Syntax

Clojure has vectors, which are accessed by integer indexes:

  [1 2 3 4]
  -> [1 2 3 4]

  (get [:a :b :c :d :e] 2)
  -> :c

In the preceding example, the initial `[1 2 3 4]` is input that you enter at the Read-Eval-Print Loop (REPL). The `->` indicates the response from the REPL.

Clojure has maps, which are key/value collections:

  {:fname "Stu", :lname "Halloway"}
  -> {:fname "Stu", :lname "Halloway"}

Sets contain a set of values, and their literal form is preceded with a hash. Here is the set of English vowels, using backslash to introduce a character literal:

  #{\a \e \i \o \u}
  -> #{\a \e \i \o \u}

Lists are singly-linked lists, and are enclosed with parentheses. Lists are special: Not only are they data, they also act as the syntax for invoking functions. The list below invokes the plus (`+`) function:

  (+ 1 2 3 4 5)
  -> 15

Collections themselves act as functions. They take an argument which is the key/index to look up:

  ([:a :b :c :d :e] 2)
  -> :c

  ({:name "Stu" :ext 101} :name)
  -> "Stu"

Enough syntax, let's get started.

Encapsulation

Encapsulation is the hiding of implementation details so that clients of your code do not accidentally become dependent on them. In object-oriented languages, this is usually done at the class level. A class has public methods, private implementation details, and various other scopes in between.

Clojure accomplishes the purposes of encapsulation in three ways: closures, namespaces, and immutability.

Closures

A closure closes over (remembers) the environment at the time it was created. For example, the function `make-counter` below closes over the initial value passed via `init-val`:

  (defn make-counter [init-val] 
    (let [c (atom init-val)] #(swap! c inc)))

Let’s break this down:

  • `defn` defines a new function, named `make-counter`, that takes a single argument `init-val`.
  • The `let` binds the name `c` to a new `atom`.
  • The `atom` creates a threadsafe, deadlock-proof mutable reference to a value.
  • The octothorpe (`#`) prefix introduces an anonymous function
  • The call to `swap!` updates the value referenced by `c` by calling `inc` on it.
  • The value of the let is the value of its last expression. This `let` returns a function that increments a counter, which is then the return value of `make-counter`.

The atom `c` is private to the function returned by `make-counter`. The only public thing you can do is increment it by one:

  (def c (make-counter))
  -> #'user/c

  (c)
  -> 1

  (c)
  -> 2

  (c)
  -> 3

The counter example returned a single function, but nothing stops you from returning multiple functions. These multiple functions can then share private state. The new version of `make-counter` below returns two functions: one to increment the counter, and one to reset it.

  (defn make-counter [init-val] 
    (let [c (atom init-val)] 
      {:next #(swap! c inc)
       :reset #(reset! c init-val)}))

This new `make-counter` returns a map whose `:next` value increments the counter, and whose `:reset` value resets it:

  (def c (make-counter 10))
  -> #'user/c

  ((c :next))
  -> 11

  ((c :next))
  -> 12

  ((c :reset))
  -> 10

Why the double parentheses above? Two functions calls: The inner function call looks up the appropriate function, and the outer one calls it.

Closing over data is far more general than the simplistic model offered by private, protected, public, friend, et al. in OO languages. By combining multiple lets and multiple return values from a function, you can create arbitrary encapsulation strategies.

Similar encapsulation possibilities are available in any language that supports closures. Douglas Crockford describes a similar idiom in JavaScript.

Namespaces

A Clojure namespace groups a set of related data and functions. Inside a namespace, a Clojure var can refer to a function or to data, and can be public or private.

For example, Chris Houser’s error-kit library implements a condition/restart system for Clojure.

  (with-handler
    (vec (map int-half [2 4 5 8]))
      (handle *number-error* [n]
        (continue-with 0))) 

In the code above, `with-handler`, `handle`, and `continue-with` are public vars of the `clojure.contrib.error-kit` namespace. The `int-half` is a demo function that blows up on odd inputs. When a `*number-error*` occurs, the handler causes execution to continue with the value 0. (Note how this is more flexible than try/catch exception handling, which cannot recover back into the middle of some operation.)

Internally, error-kit keeps track of available handlers and continues using these private vars:

  (defvar- *handler-stack* () 
    "Stack of bound handler symbols")
  (defvar- *continues* {} 
    "Map of currently available continue forms")

The trailing minus sign on the end of `defvar-` marks the vars as private. These vars are implementation details, and are invisible to code outside the `clojure.contrib.error-kit` namespace.

Immutability

In OO languages, another purpose of encapsulation is to prevent object A from modifying or corrupting the private data used by object B.

In Clojure, this problem does not exist. Data structures are immutable. They cannot possibly be corrupted, or changed in any way, period. You can write query functions that return “private” state, without any fear of data corruption.

Polymorphism

For our purposes here, polymorphism is the ability to choose a different method implementation based on the type of the caller. So for example:

  Flyer a = new Airplane();
  Flyer b = new Bird();
  a.fly();
  b.fly();

`a.fly()` and `b.fly()` do different things because they are called on different concrete types.

Clojure provides a generalization of polymorphism called multimethods. A multimethod definition begins with `defmulti`, and then has a name, plus a dispatch function that is used to select the actual implementation: To mimic polymorphism, simply dispatch on the `class` of the argument:

  (defmulti fly class)

Individual methods of a multimethod begin with `defmethod`, then the multimethod name, then the object that must match the dispatch function. Finally, you get the argument list in a vector, followed by the implementation of the method. For example:

  (defmethod fly Bird [b] (flap-wings b))
  (defmethod fly Airplane [a] (turn-propeller a))

Unlike polymorphism, multimethods do not limit you to dispatching on class. You can dispatch based on any arbitrary function of the method arguments. So for example, a bank account might have a `:type` entry that is used to determine the interest rate:

  (defmulti interest :type)
  (defmethod interest :checking [a] 0)
  (defmethod interest :savings [a] 0.05M)

The `:type` attribute is a convention, but nothing prevents you from dispatching on a different attribute, or even dispatching on more than one at the same time! For example, the `service-charge` multimethod below dispatches on two different facets of the same object: the object’s `account-level` (`::Basic` or `::Premium`) and its `:tag:` (`::Checking` or `::Savings`)

  (defmulti service-charge 
    (fn [acct] [(account-level acct) (:tag acct)]))
  (defmethod service-charge [::Basic ::Checking]   [_] 25)
  (defmethod service-charge [::Basic ::Savings]    [_] 10)
  (defmethod service-charge [::Premium ::Checking] [_] 0)
  (defmethod service-charge [::Premium ::Savings]  [_] 0)

The `_` is a legal name, and is used idiomatically to indicate that an argument will be ignored. (There is no need to even look at the argument, since all the work has been done in choosing which method to dispatch to!) This example also demonstrates two other concepts:

  • The double-colon prefix resolves a keyword in a namespace. This prevents name collisions among keywords, just as object-oriented langauges use namespaces to prevent name collisions between type names.
  • `account-level` is a function (not shown here), not a simple key lookup. It returns `::Premium` or `::Basic` based on the the account type and the current balance. Thus an account can dynamically change its account level as its balance changes.

As you can see, multimethods are far more general than polymorphism. Instead of being limited to type-based dispatch, multimethods can dispatch on any arbitrary function of an argument list. This allows programming models that more closely resemble reality: after all, what real-world entities are limited to a single type hierarchy, and forbidden to change types over time?

Inheritance

In OO languages, inheritance allows you to create a derived type that reuses the behavior of a base type. For example:

  class Person {
    String fullName() { /* impl details */ }
  }
  class Employee extends Person {
    AddressBookItem companyDirectoryEntry() { /* impl details */ }
  }

This kind of reuse is so natural in Clojure that it doesn’t even have a name. For example, here is a function that returns the full name of a person, based on first and last names:

  (defn full-name [p]
    (str (:first-name p) " " (:last-name p)))

Employees are like people, but have other properties and behaviors, such as a telephone extension. The `company-directory-entry` returns a vector of an employee's full name and telephone extension, like this:

  (defn company-directory-entry [p]
    [(full-name p) (:extension p)])

Notice that `company-directory-entry` “reuses” the person-ness of its argument `p` by calling `full-name` on it. There is no special inheritance ceremony required to set this up, you just call functions when you need them.

You can pass either a person or an employee to `full-name`. For `company-directory-entry`, though, you must have an employee. Or, more accurately, you must have something that resembles an employee, to the extent of having a `:first-name`, `:last-name`, and `:extension`. This is an example of duck typing: if it walks like a duck and quacks like a duck, we assume it is a duck, without asking it to present its `IDuck` papers.

Many Functions, Few Types

The example above demonstrates another negative consequence of idiomatic OO style: the over-specification of data types. The return value of `companyDirectoryEntry` is given its own unique type, `AddressBookItem`. Each new data type like `AddressBookItem` requires its own life-support system: constructors, accessors, `equals`, `hashCode`, and so on.

In Clojure, an address book item would simply be a vector or a map. No new types, and no life support system required. Moreover, an address book item can be manipulated with any of the large arsenal of functions in Clojure's sequence library.

To see the problem with overspecifying types, consider this method from the Apache Commons:

  // From Apache Commons Lang, http://commons.apache.org/lang/
  public static int indexOfAny(String str, char[] searchChars) {
      if (isEmpty(str) || ArrayUtils.isEmpty(searchChars)) {
    return -1;
      }
      for (int i = 0; i < str.length(); i++) {
    char ch = str.charAt(i);
    for (int j = 0; j < searchChars.length; j++) {
        if (searchChars[j] == ch) {
        return i;
        }
    }
      }
      return -1;
  }

The purpose of `indexOfAny` is to find the index of the first occurrence of one of the `searchChars` that appears in `str`. Note the unnecessary specificity of types: it works only with strings and character arrays.

Here's the Clojure version, using the sequence library's `map`, `iterate`, and `for` forms:

  (defn indexed [coll] (map vector (iterate inc 0) coll))
  (defn index-filter [pred coll]
    (when pred 
      (for [[idx elt] (indexed coll) :when (pred elt)] idx)))

Here is an example calling `index-filter`:

  (index-filter #{\a \e \i \o \u} "Lts f cnsnts nd n vwel")
  -> (20)

The expression above finds the index of the first vowel in the string "Lts f cnsnts nd n vwel", that is, 20. But `index-filter` is more general than the Commons version in several ways:

1. `index-filter` returns all the matches, not just one.

  (index-filter #{\a \e \i \o \o} "The quick brown fox")
  -> (2 6 12 17)

2. `index-filter` works with any sequence, not just a string of characters. For example, the call below works against a range of integers:

  (index-filter #{2 3 5 7} (range 6))
  -> (2 3 5)

3. `index-filter` works with any predicate, not just a test against a character array. In the example below, the predicate is an anonymous function that tests for strings longer than three characters:

  (index-filter #(> (.length %) 3) ["The" "quick" "brown" "fox"])
  -> (1 2)

That is a lot of extra power, especially given that the function is shorter, easier to write, and easier to read (given some Clojure experience, of course) than the Commons version.

Conclusion

Clojure solves the same problems that OO solves, but it solves them in different ways. Instead of encapsulation, polymorphism, and inheritance, you have closures, namespaces, pure functions, immutable data, and multimethods. Idiomatic OO gives you a bloated type system with duplicated code hidden away behind encapsulation boundaries and little hope for thread safety. Clojure offers a radical alternative: a lean type system, a rich function library, and language-level concurrency support that is usable by mere mortals.

There is a lot more to Clojure than we have covered here: lazy and infinite sequences, destructuring, macros, software transactional memory, agents, seamless Java interop, and more. But those are topics for another day.

[This article was originally published in the May 2009 issue of NFJS, the Magazine. I will be speaking about Clojure at several upcoming NFJS events, come join the fun.]

Popular Tags