Programming Environments I Have Loved

Two pieces of advice from Kevin Kelly’s 100 bits of advice I took to heart this past year. The first & riskiest was “Goofing off is highly underrated”– I’ve worked in IT in some capacity since I was 16 years old & I needed a break, so I quit my job and gave myself a travel/research sabbatical. The second is “the biggest lie we tell ourselves is ‘I don’t need to write this down I will remember it’”, so I spent time designing utilities for my “second brain” into which I’ll capture notes & quotes & fleeting thoughts during my reading & wandering time. Nothing I’ve tried quite fits the bill, org-mode is still the centerpiece of my workflow, but investment in this direction seems to pay cognitive dividends.

In between traveling & reading & goofing off I’ve played with some new (to me) coding environments. I haven’t finished much I can present– I’ll work on a project until it answers some question or fixes a problem I have, and then I’ll put it down. This is terrible material for a tech blog, but I’ve been away too long so this post is a high-level review of what I’ve played with & why & hopefully by the end of it there will be a few useful takeaways.

Clojure / Babashka / Clerk 📈

I started working on some personal scripts to capture notes to org-mode from an email account & to import quotes from Readwise. I used Babashka for this, which is a way to write shell scripts in Clojure. If you have a shell scripting need & are curious about learning Clojure, this is a great place to start. I love how bb --nrepl-server lets you just immediately get a REPL in your editor.

Clerk is a neat new entrant to the Clojure ecosystem that I used to do a port of MiniAdapton in. Basically, it is a data science notebook that integrates very well with the in-editor REPL workflow Lispers love. Porting the miniAdapton paper was fun but I soon realized that the main advantage of Adapton– providing an incremental computation interface on top of mutable operations– fits weirdly in a language like Clojure that goes out of its way to make you use immutable datatypes. It all works, it’s just not idiomatic so I dropped it.

One thing that turns me off to the Clojure ecosystem as a perpetual n00b is that things can require an intimidating level of configuration boilerplate or knowledge of internals. Both Clerk and Babashka are doing great work in that direction. Still, while using Clerk for some census data munging, I hit this (not Clerk-specific) memory usage issue. It’s totally solvable but it took the wind out of my sails & it feels like Clojure needs a full-featured equivalent to numpy/pandas to make progress in the data science space.

Common Lisp 🎵

Still enjoying the Lisp REPL experience but wanting to get closer to the machine I picked up Common Lisp to start prototyping some ideas for a tracker-inspired music sequencer which someday I’d like to put into hardware. For some reason Common Lisp feels stable & fast & Just Works in a way I don’t always get playing with Clojure. Some of this may be due to how great Quicklisp is. You type (ql:quickload "somelibrary"), Cmd-Enter and boom!– your dependency is downloaded & loaded into your namespace. Common Lisp itself is missing nice things like Clojure’s Sequence abstraction, and you need to pull in third party libraries like Series or fmap if you want pure functional primitives, but ofc Quicklisp makes that completely painless. I like being able to mix functional & imperative styles as-needed & low latency audio programming is a use-case where pure functional seemed impractical.

What I find most fascinating about Common Lisp is the way it’s a high-level language that gives you a lot of control over lower-level details, such as being able to query or pause the garbage collector, visualize the assembly output of a function, and inline function calls where needed. Performance-wise it trounces Python in terms of this level of control, so I can see how Lispers are still smarting from this instance of Worse is Better. It has tools that will autogenerate C FFIs from header files, so if you need to call out to C it’s trivial, & my project relies on the SDL2 and PortAudio/PortMidi bindings that already exist. My new preferred strategy for systems-programming type work would be to prototype in Common Lisp, then rewrite any truly performance sensitive parts in Rust or some other systems language.

Rust / Repl.it 🦀

Because someday soon I need to make money & take interviews I’m learning Rust by practicing on Leetcode. When I want a better editing environment than what Leetcode provides I move to Repl.it. I’d like to learn more systems programming & the languages I have the most experience in – TypeScript, Python– don’t provide a lot of power for the kinds of problems you get asked in coding interviews. It’s convenient to be able to use the std binary_search, or have a collection which supports custom key order without having to code one up yourself. My opinions here don’t count for much, but I enjoy the copious use of Optional & Result types & the overall system reminds me a bit of Haskell. The syntax is way better than C++ & the community has done a wonderful job with documentation & error messages. It compiles fastish but of course it’s a far cry from Common Lisp levels of interactivity. The borrow checker still trips me up & I can spend hours figuring out how I have to re-structure the problem to satisfy it. Much like the way Clojure bends your brain to think “how do I restructure this problem in the presence of immutability”, Rust bends it with respect to ownership. This isn’t always comfortable but it’s always worthwhile.

SwiftUI / Flutter / ChatGPT 📱

The latest thing I’m playing with is a Notes app in SwiftUI, targeting iOS and Mac, a playground for some UX & hypertext ideas. The short-term win would be if I can replace my use of the built-in Mac/iOS Notes app with it. I want something that lets me quickly compose/edit Markdown & Org-mode files, capture fleeting notes into those formats, and give me tools to organize & integrate them with a proper Emacs-or-other-tool-for-thought workflow. I always have my phone with me, but there’s a disconnect between what’s comfortable to do on it & the power I want when I sit down at my PC.

The original vision was a kind of grid-based canvas that I could pan over & zoom in/out of easily, but as soon as I started prototyping this using ChatGPT in Flutter I found that the widget support I was looking for didn’t exist without coding everything up on a raw canvas. Translating the same thing over to SwiftUI– ChatGPT win!– helped me discover the same issue there. (What I envisioned might be rare/impractical on mobile.) ChatGPT is amazing at getting small components in an environment I’m unfamiliar with coded up, but as soon as you’re at any kind of scale where you need to start refactoring it the interface is tedious, & the amount of code it can remember is small. At some point I will give Copilot a shot. My fears of a robot takeover are relieved but it’s a crazy powerful tool for rapid prototyping, & it’s mostly replaced my use of StackOverflow. In the end I stuck with SwiftUI instead of Flutter to learn the native Mac ecosystem, and Swift > Dart IMHO.

Conclusion 👨‍💻❤️

At the end Swift and Common Lisp have sparked the most joy. These are obviously very different languages, & useful in different contexts, but what makes them enjoyable is similar. The feedback loop, between writing code & seeing what its effects are, is very short in both environments. Short, like, a single keycombo. For Common Lisp this is at the expression level, or watching as it mutates your running environment. For Swift this is due to the SwiftUI content previews & the type checker & inline editor feedback. Both environments have “batteries included”, require virtually no setup & within a few minutes you can Just Start Working. Both environments make it easy to get inline documentation or dig into the layers below what you’re working on. They’re fast. They’re innovative, but they have established communities for whom a Google search will almost certainly help fix your problem.

Swift seems to be doing the most of any strongly typed/systems programming language to enable the kind of interactivity that Jack talks about in ‘Stop Writing Dead Programs’, which you should go watch. He’s been super helpful during my ADHD explorations so go check out his site for more resources about coding & computational creativity.

Thanks for reading & if you’ve made it this far please DM me with any thoughts, I’d love to hear from you!