Archive for October, 2011

VimClojure – Easy

October 12th, 2011 3 comments

Update 1/2013: The future of Clojuring with Vim is tpope’s foreplay.vim. You can find a tutorial here.

I promise this is the last VimClojure post for a while.

I get the feeling that my post describing my VimClojure setup is a little too involved, especially for someone that just wants something working quickly. Also, from what I’ve seen on #clojure, there’s some frustration out there. With that in mind, I put together a minimal example configuration with instructions.

So, without further ado, vimclojure-easy.

Feedback welcome.

Categories: clojure, vim Tags: , ,

Familiar: Clojure plus Ruby

October 9th, 2011 2 comments

Last week I had three separate conversations with people about using Clojure’s data structures and concurrency primitives from a language that’s not Clojure. Something about parens or insisting on using a less capable language :)

So, this weekend I played around with using Clojure from Ruby, in particular JRuby. I haven’t done much Ruby in about a year, so I spent most of my time remembering that. Anyway, I ended up with a proof of concept: Familiar. See the readme there. Here’s an example:

That’s it. This gives full access to the clojure.core API including lazy seqs, STM, and all those goodies. Good idea? Idiotic? I don’t know, but it was a fun exercise.

Categories: clojure, ruby Tags: , ,

Taming VimClojure 2.3.0

October 7th, 2011 No comments

Update 1/2013: The future of Clojuring with Vim is tpope’s foreplay.vim. You can find a tutorial here.

In honor of the release of VimClojure 2.3.0, I’ve updated my post on taming VimClojure. Thankfully, very little has changed in the setup. Cheers.

Categories: clojure, vim Tags: , ,

Clojure Update Literacy

October 4th, 2011 1 comment

I want to write briefly (ok, not that briefly) about my understanding of Clojure‘s various “update” functions, in other words, functions that take a function argument, apply it to some value and do something with the result. These include swap!, alter, commute, send, send-off, alter-var-root, update-in, alter-meta!, vary-meta, and probably several more. From here on out, I’ll call a function in this family an update function and the function passed to it a transform function.

Note that update functions are most commonly encountered when using Clojure’s reference types, i.e. vars, refs, atoms, and agents. Their signatures are all very consistent:

    (<update-fn> old-state <tranform-fn> & args)
    ;=> new-state

That they’re so consistent is a testament to the thought that has gone into the design of Clojure’s core API.

Nonetheless, a newcomer to Clojure, overwhelmed by all the other new concepts they’re learning, might find update functions a little confusing. They might find themselves calling reset! a lot because swap! is scary. Of course, if the value passed to reset! (or ref-set) depends on the previous value of the ref, you’ve thrown away all the nice concurrency guarantees that atoms and refs are supposed to give you. For example, the prototypical id generator:

  ; BADBAD Don't do this!
  (defn id-generator []
    (let [id (atom 0)]
     (fn []
       (reset! id (inc @id)))))

No No No No No

Of course, everyone knows to use (swap! id inc) for a canonical example like this, but in the thick of a larger app, feeling like you’re in over your head, it’s easier to make mistakes.

So, learning to read (and write) an update function can take you a long way along the road toward writing more idiomatic Clojure. For someone with an OO background, it might be easier if we mentally re-wrote the signature above like this:

   state = transform_fn(state, arg0, arg1, ...);

that is, we’re applying some transformation to the current value of state and storing the value back in state. See, swap! and friends are just a function call in disguise. Their signatures are completely consistent with Clojure’s argument order conventions, but they slightly obscure what’s going on because the state and transform function are switched. This makes sense since state is the important argument, but it took me a little while to realize this and make the mental adjustment.

Once I reached this conclusion, I found writing in a functional style with state transitions much more straightforward.

Note that I find this a useful way to *read* update functions. It’s not a replacement for thinking hard about the semantics of the update function you’re using

Here are some general guidlines that I find helpful:

  • Always write pure functions that represent state transitions or transformations. They take in the current state and maybe some additional arguments and calculate a new state. This is obvious, but sometimes I have to keep repeating these things to myself. Kind of like in Tcl, “everything’s a string, everything’s a string, everything’s a string, …”
  • reset! (and its cousin ref-set) is for exactly what its name says: “reset this atom back to some initial state dammit!” Only use it if you’re resetting your app, or if the new value truly doesn’t depend on the old value. In the latter case, randomly generated values or user input come to mind.
  • Always give your transform functions a name. Passing an anonymous function to swap! means you just wrote a function that’s harder to test or experiment with at the repl. Besides, a descriptive name is more readable than most anonymous functions.
  • Limit the number of call sites for update functions in your app. A system that’s sprinkled liberally with (dosync) blocks and calls to swap! will be more difficult to reason about than one where the state transitions are localized.
  • Don’t forget the args! I’ve often fallen into the trap of passing an anonymous function when I needed to pass args to my state transition function.
  • Don’t forget that most things are functions and, therefore, candidates for transform functions!
        ; A contrived example
        (def signal (atom :red))
        (def transitions { :red :green, :green :yellow, :yellow :red })
        (swap! signal #(get transitions %)) ; <- NO
        (swap! signal transitions) ; <- YES

and finally, as a wise man once said “functions and data!”

In conclusion, I hope this sheds some light on an area of Clojure that I’ve personally found to require a great deal of mental deprogramming. As I’ve gained confidence with these concepts, my code has been easier to read, easier to test, and easier to reason about. Happy Clojuring.

Categories: clojure Tags: