Code: everything is here on GitHub. There’s a handful of documented, worked examples and a Max 6 project you can launch to try everything out. As always, the wonderful Leiningen is used as the build tool.
The second niggle is wonderfully didactical: porting one of Darwin Grosse‘s interactive drawing examples (“Puffdraw”, from day 6 of the November Patch-a-day) resulted in a program which seemed to work, but constantly ran out of heap, or caused the garbage collector to blow the stack. Here are a couple of pertinent bits of the code:
|1 2 3 4 5 6 7 8 9 10||
This thing gets called rapidly to track mouse pointer movements and is also on a 30-millisecond timer; on each event a new point is added to the front of a queue, the last point is taken off the end, and the queue is redrawn on screen. (The code now uses
take instead of
drop-last, but the result is the same.)
The drawing routine looks something like this:
|1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16||
So, why does this blow up? (Let’s ignore the fact that the iteration makes the traversal complexity O(n^2) on the length.) Well, Clojure is a lazy language, so the queue generation (
drop-last) builds suspended data structures. Because the for-loop knows how long the queue is, it never attempts to read the end of it and force its complete evaluation. Result: each time the queue gets cycled with new data, a bigger suspended data structure is built, and it is never pared down by being examined to the end.