2025-12-14

12:35:15, atom feed.

Here is the commit log from this last week of work.

2025-12-08
feat: add array and slice-generation macro and test for it

What happened?! The time has come to switch off of "C++". Even my beloved dialect of C++-that-is-actually-mostly-C leaves me with lots of work to do to create a language I'm happy to use, before I can get back to the problem at hand of developing a game.

As I refreshed my memory on search algorithms and studied pathfinding algorithms I was not familiar with, I realized I'd benefit from some more sophisticated data structures. As you can see from the commit above, I started to implement such data structures. I had three options. The first was to just use containers from C++'s standard library. I really didn't want to go this route for reasons I won't elaborate on here; suffice to say that I don't plan on depending more on C++ features in general. The second was implmenting my own code generator, like spec'ing out code with variables that a (hand-written?) templating tool would replace with values like type information, running this as a pre-build step, and then including the generated code in compilation. Again, more work, essentially somewhat re-implementing C++'s template features and also portions of what the third option was: preprocessor macros.

I opted for the third approach since, in theory, it is write-once-test-a-bunch-use-without-too-much-care-afterward. The natural place for this work was in the small standard library I was growing. I did prove out that I could generate a satisfying array type and a corresponding slice type. But honestly the thought of repeating that for a queue, a priority queue, a dynamic array, a hash map, etc. dissuaded me from continuing. Not only would I need to take a lot of care to avoid bugs and write a bunch of tests, I'd also need to get into the weeds about which implementation of which data structure was most optimal (or at least good enough), etc. And I just can't be bothered right now.

Coincidentally, I came across a podcast interviewing Jon Blow (this one? I don't quite remember unfortuantely), asking about why he was creating Jai and what hope he thought he had of creating a relevant C++ competitor or even replacement. I have been spending a lot of time thinking about whether to go all-in on Jai, weighing the tradeoffs of an actually-sane language but one developed and maintained by only a very small number of people (albeit with a big flagship project proving that the language is ready for production projects) and an industry-standard language backed by tools with massive user bases and a much larger number of contributors. Jon's answer was very convincing. In short, he said that we as a species have not used the same programming language forever. Even Big Industry switches languages over time. So if we accept that we are not going to use some particular language forever, then we don't have worry about asking ourselves whether we can compete with things like C++. Instead, we have to ask ourselves, when we do have a new language that we gravitate toward, which one will it be? Jai is Jon's language in this regard.

The last time I used Jai seriously was one year ago, last winter. Back then I wrote essentially what I have now in "C++" and SDL (load tilemaps and sprites, paint a level and a character, move the character around in a 2D world) but in Jai and its built-in windowing abstraction called "Simp." So I spent a couple days brushing up on the language and learning about what had changed since when I last used it. After refreshing, I gave a Big Think over whether or not to use Simp again for my project. I decided against it and chose to stay with SDL. So I started exploring Jai's bindings generator tool that is often used to generate Jai bindings to useful C and C++ utilities people want in their Jai projects. At the time of this writing, there is an open-source repo that uses the bindings generator to create SDL3 bindings for Windows, macOS, and Linux. I forked it and modified it a little to support my own workflow. Instead of the current open-source behavior which wants a system-installed SDL3 library at least for the Linux use case, I compile SDL3 from scratch for my project and so want to point the bindings generator at that library at generation time. I got it working in the end but suspect I was holding the tool wrong because there was some non-obvious behavior such as transforming things like ../../build/libSDL3.so to __/__/build/libSDL3.so which broke library loading at runtime untils I made some manual tweaks to the generator and also stuffed a library in my source code instead of just in the build/ folder. So despite it working, I wondered if there was an easier way overall.

Again coincidentally I came across some videos on YouTube about using Odin for game development. I've known of Odin for years but have never gotten into it. Odin does provide SDL3 bindings out of the box. Although not shown in the commit log at the beginning of this post, I've started down the Odin path, first to see if I enjoy the language enough to keep using it and second to see if it's any easier (by my taste) to achieve what I'm trying to do with Odin than it has been with Jai.

Currently I am opening a window via SDL3, painting the window the same gray background color I was using in my previous C-like implementation, and reacting to window-close events. The magic to work with my compiled SDL libraries is simply:

  1. build SDL3 and emit libraries in ./build

  2. build my Odin project as follows

     odin build src/ \
       -extra-linker-flags:"-L./build" \
       -out:"./build/game" \
       -show-timings
    

Now, I am working on porting all my other code from "C++" to Odin. It's annoying, but it's best to pay this language-and-tooling cost up front in the project and have a consistent set of tools I enjoy using for the life of the project, which will likely be years.

So far, I think Jai is simpler than Odin, both in syntax and in its concepts. There are very many similarities in the language behavior and syntax. I cannot tell who inspired whom, presumably Jon-->Bill? Regardless, Odin hasn't been hard to pick up. The thing I spend the most time on is figuring out which types I should replace C-style buffers and arrays with in Odin. I'm only a couple days in, so maybe this is obvious and simple, but I'm just not there yet, have been playing more with SDL3 and doing a lot of reading about Odin to get a sense for its capabilities and staying power.

I did find one thing amusing, that there will be an upcoming change, part of which is explicitly passing an allocator into some functions (ref). I am already doing this everywhere in C, so no big deal. Jai passes a context to every Jai call that provides things such as an allocator so that callers can easily swap out the allocator used by third-party code, unless the library author explicitly chooses to ignore the requested allocator. I think Odin has something similar.

Next week I hope to have at least my previous game implementation but this time in Odin, if I don't decide to switch off of it.