
writing and debugging some leetcode in the otium terminal multiplexer
A long time ago (nearly a decade ago now), I set out to develop a programming language. In the arrogance of youth, I felt like I could do a bit better than what existed, and instead I went down an educational rabbit hole learning about how to make programming language runtimes, while making a pretty bog-standard Scheme implementation.
I think I owe whatever shreds of talent I have to that little months-long project though. It’s a topic that’s continued to fascinate me even though I never had the time to pick it up once I started working full time.
I read a lot of folks suggesting that new languages are now dead on arrival: either because LLMs will be dramatically better at writing in existing languages in their training set and thus people will never adopt new languages, or because language choice no longer matters (at least to most people) and thus there’s no point in exploring the design space any further.
I don’t have an answer to this. I think both arguments have some merit to them and it’s a sad thought that we’re frozen in 2023 as far as language design goes. But I’ve also been hacking on a language in my spare time and it’s given me some things to be optimistic about as well, which I thought I’d share here.
Can I suggest that Lisp or a language with S-expression syntax is actually excellent for this moment? Agents are good at writing it, don’t get tired of balancing parentheses, and given that most code is not written by humans anymore, it makes sense to spend your novelty budget on more interesting areas like type systems or the concurrency model than on syntax.
I’ve actually been contemplating this article for a while, and early last year my plan was to make some evals seeing how many turns it would take LLMs to create working simple programs in a novel language vs. the Python/TypeScript etc. they were already oneshotting.
But as I’ve actually been hacking on this last month it seemed pointless to do because as far as I can tell, agents are fine with a goofy half-baked Lisp dialect that has just enough different about it to be confusing to anyone with a background in one of the established Lisps. They one shot things as easily as I’d expect them to in Python.
There’s a massive amount of code that goes into making the ecosystem of tooling and library support around a language and relatively little of it that you can do differently in a way that makes your language better. It’s required but low value.
Need a formatter? A linter? How about bindings to graphics libraries or SQL databases? LSP server for an editor? This was previously lots of work and a large maintenance burden, but now you can have it all on a hobby weekend project.
The formatter and linter you’ll probably want sooner rather than later for reasons of code quality and just keeping it readable.
I find dropping in to write programs by hand to be quite useful, because I catch goofy things that the LLMs have done. It also pleases me that I find the language fairly easy to write code in compared to the Scheme I made a long time ago. So far I’ve just been doing leetcode but as my UI libraries and development environment stabilize, I’m planning to do more of it in there as well.
I’d rate myself as pretty novice, maybe somewhere between novice and intermediate, in the area of programming language design & implementation. That said, even with my limited experience I can still find all sorts of ways in which they fall short of implementing my intent.
For example, I’d like this programming language runtime to work well on embedded devices with multi-MB of memory, like the ESP32 and RP2350 platforms. This is part of the AGENTS.md as well as my prompts, but I’ve still ended up with a ton of stuff that would prevent this from actually working, like executable code space never being cleaned up and tons of dynamic memory allocation for normal language features.
At Recurse we say to work at the edge of your abilities. One antidote to feeling like agents are going to replace you this soon is to find the edge where yes, you still need to dig into the code and figure out what’s going on in order to make the thing work as intended.
OK, haven’t cracked this one yet. Paying a little bit of attention to make sure the actual ordering and examples makes sense has been useful, but they’re still pretty rough.
I have no particular aims with my language project other than personal amusement, but I would love to see someone seize the opportunity presented here and take things in a more extreme direction. Maybe we can just rewrite everything with dependent types? Or should we be leveraging proof checkers as part of the language?
I think getting a new language going is harder than it already was (which was pretty hard!) but on the flip side agents will slog endlessly through the details if you can convince people on higher level merits, like programs that have fewer bugs in them.