Last week I saw a breathless headline on proggit about clojure and Brian’s functional brain: http://blog.bestinclass.dk/index.php/2009/10/brians-functional-brain/, written by Lau.
As a Common Lisp programmer, Clojure irritates me for various irrational reasons. As an exercise in breaking those down, I ported Lau’s 67 line program (which had no comments) to CL running on SBCL using asdf-installable libraries. I used lispbuilders-sdl for display and pcall for concurrency. I ended up with 115 lines, including comments and some significant differences in the program.
I went through a few revisions, initially trying to transliterate the code, looking at the fine clojure API docs to figure out what different things did. Then I gave up on that wrote more idiomatic (at least for me) lisp, but still resisted the urge to use iterate of alexandria. I wanted to have code that was as close to the bare language as possible, so I could make an apples-to-apples comparison. Now that the exercise is done, I think that goal was unattainable. It’s close, but the differences in the languages are significant, so it’s not an great comparison.
After the first round, I started diverging more from the Lau’s version, looking for higher FPS and nicer lisp. I ended up with a few major differences:
- I used a 2D array to represent the world, the Lau used a single long vector and I didn’t quite understand how it was determining adjacency
- I had a lot more functions to abstract out that data structure choice (ie: instead of calling aref everywhere, I made a get-cell function)
- Lau called pmap function to calculate each cell’s next value in parallel, and I used pcall to calculate the next whole world state while the main thread rendered.
- Lau drew boxes for each rendering loop, I made two SDL surfaces up front and blitted them in at the right spots
I spent a little under 4 hours playing with it, and a lot of that was reading documentation. I don’t think any conclusions can be made from this for a “common lisp vs clojure” flame war, these are both fairly throw-away pieces of code. I have no doubt that any experiences lisper or clojurer would find a lot of obvious improvements.
Some of my observations along the way:
- getting the lisp libraries to work (which I’ve done in the past) is probably harder than getting clojure working and using java libs.
- java libs look like a pain in the ass. This softens the “and you can use java libs!” selling point of clojure for me. They’re still java libs.
- The places where clojure calls java are kinda ugly, it’s a square peg in a round hole.
- clojure has a ton of lazy-evaluation semantics built into the language. In this case, that seemed to be a bad thing, and most of Lau’s code was calling some wrapper function to say “no really, I want you to actually do this”.
- Clojure has more syntax than I thought, using # % [ ] _ to mean different things (maybe in different contexts?).
- I’m not sure how the STM features I’ve heard a lot about come into play here, if at all.
- I should be asdf loading my libs in a nicer way, right now you need to evaluate those first lines, and then compile the file. I didn’t have the motivation to create an .asd file or finally learn how to use eval-when properly.
- I like long, descriptive function names. Some of the ones from clojure irriated me: doall, doto. It reminds me of arc a little.
- I was confused by the per-cell parallelism in the clojure version (I think clojure uses native threads in a threadpool). Pcall does the same thing, but I figured I’d be spending more time context switching than calculating, and it was getting late.
Anyhoo, a fun sunday evening.
Code is on github: http://github.com/ryepup/sandbox/blob/master/brain.lisp