The first version of Retrograde was initially named “JoyCom”1 and I was using it as an excuse to learn as much as I could about low-level programming and computer architecture. This platform was written entirely in C and included a C SDK for creating games on the platform.

Wanting to understand more about how C itself works, I created an assembler and linker for my fantasy console (using Go) which I would then create a custom C frontend for.

While creating this C frontend, I found myself wanting to make adjustments to C’s syntax to smooth out some of the rough edges and make it feel more modern. This is how JoyC2 (pronounced “Joyce”) was born.

#Expanding the scope, as one does

After working on JoyC for a while, I wanted to see if I could actually use it to write more of the console’s codebase. This is when I decided to just add the option to transpile JoyC code down to C99 code that could be compiled with any C compiler. This opened up the option to use JoyC for more than just my fantasy console.

Not A Totally Novel Idea

JoyC’s absolutely not the first to do this with other languages like Zig and Nim starting out using a C backend and other languages like V and ZenC committing to this approach as their primary backend.

This was surprisingly easy to do, considering how much of JoyC’s syntax is just C. Most of the AST that I was generating for JoyC could be directly translated to C code with only a few adjustments. The main challenge was dealing with some of the more complex preprocessor macros and ensuring that they were correctly expanded and translated to C code.

I would say the trickiest part of this process, other than parsing C’s syntax, was trying to account for cross-platform differences in how certain features were implemented in C. In the end, the cross-platform shims might actually be JoyC’s most valuable feature as it does reduce a lot of the boilerplate involved with writing cross-platform C code.

#Trying to avoid the need for build systems

Another feature I eventually added to JoyC was avoiding the need for Makefiles and other build system toolchains by adding in-source directives for defining link flags, compiler flags, and so on. This means you can just run the CLI tool on a JoyC source file and it will automatically attempt to discover and compile any dependencies, then link everything together and produce an executable (similar to Go).

Eventually I would draw even more inspiration from Go and add commands for fetch and vendoring dependencies in the .joyc/ cache directory, which would allow you to easily manage third-party dependencies in your JoyC projects without needing to worry about setting up a separate package manager or build system.

#Some sample code

Here’s a sample showing off some of the syntax and features of JoyC:

#include "joyc/memory.jc"
#include "joyc/io.jc"

struct Point { i32 x; i32 y }
enum Direction { North, South, East, West }

void move(Point *p, Direction dir, i32 dist) {
    switch dir {
    case Direction.North: p.y += dist  // auto-deref
    case Direction.South: p.y -= dist
    case Direction.East:  p.x += dist
    case Direction.West:  p.x -= dist
    }
}

i32 sum(i32[] items) {
    i32 total = 0
    for usize i = 0; i < items.len; i++: total += items.ptr[i]
    return total
}

i32 main() {
    Point p = { .x = 0, .y = 0 }
    move(&p, Direction.North, 10)

    i32[5] nums = {1, 2, 3, 4, 5}
    printf("sum=%d, pos=(%d,%d)\\n", sum(nums[:]), p.x, p.y)

    char *buf = malloc(256)
    defer free(buf)

	return 0
}

Eventually I began scoping more and more features for JoyC and began proposing a broader set of goals for the language, like adding methods, monomorphic generics, and a more modern syntax. JoyC would eventually be abandoned in favor of Conjure.

#2026 Update

I recently decided to use Claude to help me finish up some of the remaining features and bugs in JoyC to get it to a usable state. I’ve even started putting together a little website for it. Once I’m happy with the state of the project, I’ll make it publicly accessible, though it’s not a priority for me at the moment.