Updates on 2021/10/11

An epiphany I had while preparing for a Metamuse podcast recording and reading through an old Hacker News thread on building my own software ecosystem -- none of this is really about productivity. It's pretty difficult to make the case, even if I can build these things quickly, that my time is not better spent elsewhere.

I think more importantly, building your own tools and software is about changing your relationship with the software that runs your life. Maybe I don't get more work output per hour of time invested, but I trust my tools more, it feels more ergonomic, and there's an intangible benefit to a deeper, more durable relationship I can have with the tools that I have my hands on for so many hours of the day.

As of this week, Oak is at a stage where what I consider "basic" features of the language and surrounding tools are done. These include

  1. The oak interpreter (obviously)
  2. Syntax highlighting in my editor of choice (Vim)
  3. Automatic code formatting (oak fmt)
  4. Compilation and bundling to single-file programs, especially to JavaScript/the web platform
  5. Basic standard libraries, including a Markdown renderer and date/time utilities

It puts Oak at toolchain feature parity with Ink where I left off with it, and makes me very comfortable to finally build on Oak, rather than simply work on Oak the language and toolchain.

Since I've gotten to this point, I've found myself keeping a terminal tab with an Oak program and a repl open, and tinkering and playing with it from time to time. Mostly writing programs that don't do anything special, like:

std := import('std')

Message := 'Hello, Mac!'
len(Message) |> std.range() |> with std.each() fn(n) {
	std.println(Message |> std.slice(0, n + 1))
}

Nonetheless, I enjoy it and it occasionally leads to interesting hacks. It's making me think about whether being able to play with a tool is a vital aspect of a good tool. Play is where a lot of discovery and divergent thinking happens, and where a tool can really come to feel right in your hands.

I've spent a bunch of the last weekend and some of this week working on oak build --web -- the Oak language toolchain feature that lets an entire Oak program (across multiple files) be cross-compiled into JavaScript, to run in browsers or on Node.js/Deno. I've done this once before for Ink with September, but there are a few improvements in the way I'm doing oak build.

  1. Most obviously, oak build is a command built entirely into the interpreter binary. Even though it's written in Oak (and therefore self-hosted), the whole thing is baked into the oak executable. This means no need to clone a separate repository / project like September. It also means it gets tested with the language's standard library tests, and that I can assume every language user has it.
  2. Speaking of tests... oak build outputs are continuously integrated against the entire Oak standard library test suite, which is something that wasn't possible with September because...
  3. oak build can take a single entry point program file and recursively follow top-level static imports to figure out which other files need to be included in the compiled bundle (including standard libraries for the JS output). No more passing multiple files to september translate.

As with many other parts of Oak, I'm really appreciating the opportunity to make architectural decisions with experience "from the field" to design with much more foresight than my first attempt.

Specifically, I'm pretty proud of the fact that oak build's current architecture lets all of the tokenizer, parser, static analyzer, bundler, and some of the code generator share code between compilation targets (Oak and JS), yielding a much more maintainable codebase.