Dōji Devlog #1: Garbage Collection

So it turns out the key problem to solve early on is how values in Dōji will be represented, which leads to the challenge of designing a garbage collector.

It would've be quite simple to import abdwgcwrapper and be done with it. But it'd be far more interesting to build it myself, and I was right. So far, I've built an incremental mark-sweep garbage collector, but plan to improve it later on.

I initially wrestled with the interface design, considering using anObjecttagged union (messy) or a fully generic Zig allocator (not enough info, very difficult).

Eventually, I came up with a way to define the object types that will be allocated at comptime (thanks to Zig's strong support), and then tagging the objects at runtime. We can then statically define a tag-type map, which solves many challenges like

  1. storing per-object metadata (e.g., color)
  2. tracing references of an object
  3. centralised finalization of objects.

Each allocation allocates some additional space before the object for metadata. This is minimally 8 bytes, but is dependent on the alignment of the object types. Using the tag stored in the metadata, we can then cast object pointer to the right type at runtime, and call the trace and finalize methods on these objects.

Here's the GC interface that I've come up with:

const GC = doji.GC(
  // object types
  .{ String, List, Map, Fiber },
  // other config
  .{}
);

var gc = GC.init(allocator);
defer gc.deinit();

const string = try gc.create(String);

Best of all, most of the object type manipulation happens at compile time, which means a compile error is produced should anything be invalid!

Here's the code for this garbage collector design. In the next devlog, we can discuss value representation!

Dōji Devlog #0: ???

Welcome to the first devlog entry of Dōji, a simple scripting language that I'm building!

Most of my knowledge of programming languages and interpreters comes from the amazing Crafting Interpreters book by Robert Nystrom, but that doesn't (yet?) cover a bunch of features that most modern languages have.

So I'm building Dōji to learn about these missing features. This includes

Dōji will mostly look like JavaScript, with some simplifications, different keywords and pattern matching. Here's a snippet of the syntax:

let { Debug } = import "std";

let my_first_fiber = spawn {
  Debug.print("Hello from my first fiber!");
  21
};

let my_second_fiber = spawn {
  Debug.print("Hello from my second fiber!");
  21
};

let my_first_result = resume my_first_fiber;
let my_second_result = resume my_second_fiber;

Debug.print("The answer to life is {my_first_result + my_second_result}.");

Oh, and the name Dōji is just "concurrent" in Japanese. I’ve learned that translating random words to Japanese is an easy way to create (mostly) unique and very pronounceable names.

You can check out the code for the project here. That's all for now, onwards to the next devlog entry!

Hello, world!

I wanted to write more frequently, but in smaller chunks, and I think the microblog format suits me the best (at least for now). This site aims to capture my "stream of consciousness", which usually includes content about compilers, programming languages and web development, but also probably some life update stuff along the way.

Right now, this site supports basic Markdown with headings, links, bold and italic text, quotes, and code. I’ll aim to support images and other embeds in the future!