/tinyletter

The Programs of the First Week of 2016

This Week’s Program: Jan 4 - Jan 8

I hope ya’ll are feeling resolute this week.

Last week, I teased at introducing core.async into my program. I didn’t quite get there, but I did make some intermediate steps in building a more deterministic control flow.

d7cfee28601670e0897edaeadd4112b5031dda00

Previously, I had been using Overtone’s built-in event system. I am a middling computer scientist, but in my experience event listening and triggering systems are not great at articulating the control flow of a program. In this particular case, the play function sends a message to the SuperCollider server and then schedules itself with temporal recursion to do that again. This occurs on a separate thread, allowing the main process to continue. This is great for live coding exercises because you can continue to call functions and send input while it processes in the background. But my main function is synchronous and imperative in its nature: It starts recording to a path on the filesystem, it plays music, when the music is done it stops recording. With the event handles, this synchrony is not immediately apparent.

Enter Clojure’s promise. In this commit, I’ve removed the event handling and instead added an additional parameter to the play function: a promise that the melody will complete. When deref is called against the promise (the @ character is some Clojure Reader sugar), the thread will block until the promise has been realized with the deliver call. Instead of triggering the ::finished-playing event in the tail call, I deliver the metronome as the value to the promise. As a result, the main function reads in the order it executes. Synchrony is enforced around asynchronous internals.

ef118b13ad61b00d14b55f70b84619bc172d0d34

The next step I took was to change play to be a multi-arity function. Now play has two forms: it either accepts two parameters: the metronome and the melody, or it accepts those plus the promise. In this way, the 2-arity form returns a promise to the caller, while the 3-arity form is used internally for the purposes of temporal recursion. I thought this was a pretty clever trick.

7cdb4864e07cf2c171d05f748481be11b65104a7

Here’s where the week got thrown off a little. I was pleased with my promise implementation but I still wanted to explore how core.async could make this that much more deterministic. So I added it as a dependency. I also decided to take this time to upgrade my Emacs packages, including CIDER and its associated nREPL plugin. Afterward none of my Clojure programs would run, not even Leiningen. After some googling and digging, I realized that even though I thought I had Java 8 on my system, my Mac was still using the Java 6 JRE that is shipped by Apple. After some brief confusion on the Oracle website (I thought I had downloaded the JDK but really I downloaded the JRE which installs itself in a directory called “Internet Applets” or some malware-looking thing) I finally got it sorted. It’s this kind of shit right here…

Communicating Sequential Processes

Here’s a brief diversion on some of the background material about why I think core.async is cool and why I’m really keen on the CSP model.

Effectively, what really interests me in the CSP approach is this idea of enforcing synchrony around inherently asynchronous activity. Nearly all apps these days do something that can and should happen in separate threads or processes. The challenge is in coordinating these disparate activities into a single deterministic thread of execution. Another compelling mode of thinking about this challenge is Railway oriented programming (Google it) which describes how execution occurs linearly throughout a system but diverges in failure states. CSP and the use of communication channels seem to support this kind of thought. FRP and Signals is another line of thought. It’s all really interesting to me…

Another way to think about this as it relates to sonic-sketches: Reading a promise (with deref) blocks until something has been written to it (with deliver). When coordinating on a CSP channel, the Writing process blocks until a Reading process begins.

Next week: more concurrency thinking. More synchrony.

I hope you’re enjoying this TinyLetter. If you are, I’d really love to hear your thoughts. Reply to this email or write me a tweet.

Your friend in 2016,
Mark