Weeknotes 2025 W47: leip.zig
Quick bits:
-
It’s Tortensonntag! Pie Sunday! If I am not mistaken, this means that it is mandatory to eat pie today.1 [Ugh. It’s Totensonntag, you fool. — Ed.]
-
More and more websites quietly and automatically translate content from its original language (often English) to German, despite my system language being set to English. I virtually never want to read an automated German translation. I hate this trend.
I even started being pushed towards a fan version of The Magnus Archives in German rather than the official version. Das Magnus Archiv. How bizarre is that?2
-
It has become the time to make spiced coffee. A bit of cardamom makes a big and nice difference. The rest of my spice blend is secret.
-
Firefox on iPhone has become wildly slow. Opening and closing tabs takes about three seconds. There is an open issue for it, which I hope gets resolved quickly.
Shower thoughts:
-
Sometimes when I’m on the train and I see an older woman read a romantic novel, I like to imagine it’s a very dark psychological thriller instead. What’s going through her mind? What is she secretly excited about?
-
Sometimes when I feel that I am getting old, I remind myself of the fact that I have never seen a punch card in real life.
-
Stop procrastinating. Put it off now.
-
We need a Zig library called Leip. This is the only way we’ll get Leipzig.
I published a new Nanoc release, v4.14.3, with a performance improvement that could be huge in certain situations, specifically for items3 that depend on many other items, like sitemaps and feeds.
When I removed the use of fibers from Nanoc, I accidentally created an unanticipated slowdown. This new Nanoc release fixes that performance problem, and even goes beyond that. Nanoc v4.14.3 is the fastest release yet.
The way Nanoc used to compile items is as follows:
-
Find all outdated items. Those are the items that have changed since the last compilation, or that depend (directly or indirectly) on items that have changed.
-
Stick all outdated items in a queue, and compile them one by one.
-
When an item fails to compile because it depends on an item that needs to be compiled first (e.g. the blog archive page containing the list of posts), then that item (e.g. the blog archive page) is deprioritized, and the item that is depended on (e.g. a post) is prioritized in the queue.
This algorithm produces correct results, but can get quite wasteful in some cases. Consider the compilation of a web site where one blog post (numbered #1) is changed:
-
Nanoc picks the blog archive page as the next thing to compile.
-
The blog archive page fails to compile, because it depends on blog post #1.
-
The blog archive page is deprioritized in the queue, and blog post #1 is prioritized.
-
Blog post #1 is compiled.
So far so good, but the exact same cycle happens again for blog post #2:
-
Nanoc picks, again, the blog archive page as the next thing to compile.
-
The blog archive page fails to compile, because it depends on blog post #2
-
The blog archive page is deprioritized in the queue, and blog post #2 is prioritized.
-
Blog post #2 is compiled.
The same for blog post #3, #4, #5, etc. The blog archive page will fail to be compiled an excessive number of times.
The solution that Nanoc v4.14.3 brings is to not only prioritize the item that is depended on (e.g. a blog post), but also every dependency that is known from the previous compilation run. This way, when the blog archive page is once more at the head of the queue (about to be compiled for the second time), all the blog posts will have been compiled already.
It might seem excessive to compile items that are not outdated, but Nanoc’s compiled content cache makes this very fast.
With that change, my web site compiles about 10× faster. Not bad.
I’ve been working on a port — of sorts — of benchmark-ips to Zig. I like benchmark-ips because it avoids guessing the iteration counts; you set the warmup time and benchmark time (e.g. two seconds and five seconds, respectively) and the benchmarking tool will figure out how often to run the benchmark. Easy!
Here’s some example output of my Zig benchmarking library:
fib fast 689.05M (± 0.02%) i/s
fib slow 3.72k (± 0.01%) i/s
In this example, fib fast is a non-recursive, iterative implementation of Fibonacci, and fib slow is an inefficient recursive implementation. Those are implemented as functions with no parameters and returning void:
fn benchmark_fib_fast() void {
// …
}
fn benchmark_fib_slow() void {
// …
}
And here is the configuration of all benchmarks:
const jobs = [_]benchmark_ips.Job{
.{ .f = benchmark_fib_fast, .name = "fib fast" },
.{ .f = benchmark_fib_slow, .name = "fib slow" },
};
try benchmark_ips.run(allocator, jobs[0..]);
The library works well enough already, but I’ve nonetheless got quite a few things left to do:
-
Comparison: Show which variant is the fastest, and by how much.
-
Tests: There are no tests at the moment. Zero.
-
Correctness: I think the calculations are correct. But how do I know for sure? How do I verify that the statistics are sound? I’m not good at statistics, so this problem is going to suck.
-
Accuracy: Benchmarking is hard, and I want to make sure I accurately perform time measurements. This involves letting the optimizer not accidentally optimize away instructions that would be there in real-world situations, and keep the measurements as tight as possible, without overhead.
This library is not public yet. Once I tackle these to-do items, I’ll publish it. Probably.
What should I call it? Hear me out: what about Let’s Examine Instructions Per second in ZIG? leip.zig? Yes? Yes? YES?!
I was excited to hear about a new Zig book — zigbook.net — only to realize it is, well, hot garbage.
It’s not just the blatant mistakes. The writing itself is bizarre, with the author unable to distinguish between what is important and what is not. Take the first chapter, Boot & Basics, which has vast amounts of irrelevant nonsense, or the advanced build system chapter, which bizarrely describes CMake, or this issue which reveals how little the author understands. Despite the author’s clear claims, it’s all but guaranteed that this book AI-generated garbage.
It’s got all the marks of a grift. The zigbook author runs several fraudulent GitHub organizations (1 , 2, 3) for which he solicits donations, runs sockpuppet accounts, and uses the R word to dismiss AI complaints. It doesn’t end there. Red flags all around.
Why do people do this? What is the point of creating something that is so bad4 to the point of being unusable? What is the end goal here? What’s the gain?
Zig itself, fortunately, is still great! If you want to learn Zig, I recommend the official documentation. I also think the Ziglings exercises are an excellent resource.
Paul Hudson shared an interesting problem with Swift’s replacingOccurrencese(of:with:) method, and I realized the same problem occurs in Ruby.
Take a look at this:
'🇨🇦🇺🇸'.sub('🇦🇺', '🇳🇮')
# => "🇨🇳🇮🇸"
Whoa.
The blog post explains why. It makes sense why this behavior is what it is, but still surprised me. There is, unfortunately, no safe Ruby method that doesn’t have this problem.
Entertainment:
-
I started watching the original The Twilight Zone5 episodes (season 1). It holds up remarkably well, for the most part, despite it being 65 years old. The tropes are a bit predictable, but then again: it’s 65 years old.
I got the motivation to start watching The Twilight Zone from the Night Springs episodes in the Alan Wake games.6
Links:
-
Why Do Nightclubs in Movies Look Like That? (Eleven Yearz): Of course it talks about that excellent club scene in Blade.
-
“The Fall Of Icarus”: You Have Never Seen An Astrophotography Picture Like This!
-
The Brainrot Apocalypse (a DIY survival guide) (struthless)
-
Silksong and the Biblical Apocalypse (Jacob Geller): Spoilers, obviously (for both old and new testaments, Jacob said). I’m not going to play Silksong (not my type of game) so that’s OK with me! (Nebula link)
-
Monotype font licencing shake-down (Insanity Works / Ameel Zia Khan): Wow, fuck Monotype.
-
So I'm in the Epstein Files (Rebecca Watson (Skepchick))
Tech links:
-
AI world clocks (Brian Moore): Excellent. Terrible. Both.
-
Ray Tracing in One Weekend: Something on my list of things to do at some point. Sounds like a fun project!7
-
strace-macos: Ooh. This sounds incredibly useful!
-
Cloudflare outage on November 18, 2025: I’m a sucker for postmortems.
-
Coincidentally, Nanoc said “Site compiled in 3.14s.” Look! It’s pie! ↩︎
-
To be clear, I’m not saying the German fan version is bad. I’ve not listened to it, and I don’t intend to. Maybe it’s good! But I am certainly not the intended audience. ↩︎
-
The term “item” refers to pages, but also CSS files, images, and pretty much any other piece of content. ↩︎
-
Like all AI-generated content, it looks good on the surface. It looks well-structured and pretty. But once you start digging into it, it all falls apart. ↩︎
-
The Twilight Zone (Cayuga Productions, CBS Television Network, 1959). ↩︎
-
Alan Wake II (Remedy Entertainment, 2023), published by Epic Games Publishing. ↩︎
-
I do not have enough projects already, you know? ↩︎