Weeknotes 2025 W47: leip.zig

November 17​–​23, 2025

Quick bits:


Shower thoughts:


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:

  1. 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.

  2. Stick all outdated items in a queue, and compile them one by one.

  3. 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:

  1. Nanoc picks the blog archive page as the next thing to compile.

  2. The blog archive page fails to compile, because it depends on blog post #1.

  3. The blog archive page is deprioritized in the queue, and blog post #1 is prioritized.

  4. Blog post #1 is compiled.

So far so good, but the exact same cycle happens again for blog post #2:

  1. Nanoc picks, again, the blog archive page as the next thing to compile.

  2. The blog archive page fails to compile, because it depends on blog post #2

  3. The blog archive page is deprioritized in the queue, and blog post #2 is prioritized.

  4. 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:

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:


Links:

Tech links:


  1. Coincidentally, Nanoc said “Site compiled in 3.14s.” Look! It’s pie! ↩︎

  2. 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. ↩︎

  3. The term “item” refers to pages, but also CSS files, images, and pretty much any other piece of content. ↩︎

  4. 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. ↩︎

  5. The Twilight Zone (Cayuga Productions, CBS Television Network, 1959). ↩︎

  6. Alan Wake II (Remedy Entertainment, 2023), published by Epic Games Publishing. ↩︎

  7. I do not have enough projects already, you know? ↩︎

You can reply to this weeknotes entry by email. I’d love to hear your thoughts!
If you like what I write, stick your email address below and subscribe. I send out my weeknotes every Sunday morning. Alternatively, subscribe to the web feed.