Weeknotes 2025 W44: Ernestina
Quick bits:
-
I got a message from a recruiter asking me whether I’d be interested in a career at an AI company in the defense industry. You know, building military drones and stuff.
Yeah. Absolutely the fuck not.
-
Autocomplete on iOS has been getting so much worse lately. Swiping the word “questions” on my iPhone now yields “Ernestina.” Ernestina?!
-
I nearly fell with my bike as I cycled through a pile of mushy dead leaves. I skidded and slipped but managed to keep upright. That could’ve been quite a nasty crash.
I am back to health, but still feeling the residual effects of what must’ve been a severe cold.
Being back to health, I was looking to resume our TTRPG sessions, but alas — someone else in our group now fell sick, and so it’ll have to be delayed for a while longer. There sure is something going around. It has been more than a month ago that we scoundrels pulled off a score in the darkness of the city of Doskvol.
I pushed a Nanoc patch release with primarily some runtime performance improvements. These certainly are micro-optimizations, but they’re worth it nonetheless.
Take a look at this:
def direct_predecessors_of(to)
@to_graph.fetch(to, Set.new)
end
Rather than creating an empty Set over and over again, it’s faster to reuse an empty one:1
EMPTY_SET = Set.new.freeze
def direct_predecessors_of(to)
@to_graph.fetch(to, EMPTY_SET)
end
Or take a look at this:
@vertices[v] = @next_vertex_idx.tap do
@next_vertex_idx += 1
end
Removing #tap makes it faster:2
@vertices[v] = @next_vertex_idx
@next_vertex_idx += 1
In the past, I’ve done optimizations such as replacing loop do … end with a while true … end. The latter is distinctly non-idiomatic Ruby, but if it has significantly better runtime, then I think it worth it.
I’ve also removed fibers from Nanoc. Fibers bring quite some complexity with them, and I don’t think the complexity is worth the gain.
Additionally, I’ve removed some threading that wasn’t pulling its weight. In Ruby, the global interpreter lock prevents more than one thread from running at the same time anyway. Removing threading, therefore, not only simplifies the code but even improves performance by removing the overhead of context switching.
Ahh, how nice it is to make code faster by simplifying it.
With some changes to my personal web site, my entire web site now compiles in about 8s, which is good enough. For now.
One particular reason why I like Zig: you can put the tests right next to the code.3 Like this:
pub fn addWrite(
self: *Self,
allocator: std.mem.Allocator,
data: []const u8,
) Error!void {
// [snip]
}
test "addWrite() simple" {
// [snip]
try assembler.addWrite(
std.testing.allocator,
"bloop"
);
// [snip]
}
// [snip]
I’ve always admired the Ruby community for having such a strong focus on automated testing. But this week, I found myself annoyed at having the code and its tests so far apart from each other. Code and tests live in separate top-level directories; they couldn’t be further apart from each other:
lib/nanoc/core/compiler.rb
spec/nanoc/core/compiler_spec.rb
I’m now pondering whether it would be possible (and reasonable) to put specs in the lib
lib/nanoc/core/compiler.rb
lib/nanoc/core/compiler_spec.rb
I miss the Zig/Go/Rust approach. I love having tests that live in the same directory — or even in the same file!
My fiction writing sure has taken a back seat lately. I’ve not published anything in over a year. Oops!
Since it’s November, and November used to be National Novel Writing Month (in the U.S.), I’ve been thinking of deliberately making more time for fiction writing.
I’ve got plenty of drafts lying around, written on loose sheets of paper with various colors of fountain pen ink. There’s enough material to create more than a few cohesive stories.
Maybe I’ll continue with the Alphabet Superset? I’ve missed the (soft) deadline by, erm, years. Not that a deadline matters, though.
It’s not just my fiction writing that has taken a back seat. I’ve not done too much technical writing either. I’m a bit surprised by that myself, as I’ve had quite a bit of time, being unemployed and all that.
I’ve got a few drafts of articles, but none of them are even close to completion. In all likelihood, 2025 will be the first year where I don’t publish any articles at all, breaking my streak since I began in 2020.
I still have time to write something, of course — but I’m not going to write something just for the sake of writing something.
My interpreter book is on ice, in large part because the existing implementation uses Ruby and the book is written with a Ruby audience in mind, but at this point I think that Ruby is just not the right choice of language anymore. Also, given the existence of the excellent Crafting Interpreters book and the Writing An Interpreter In Go book, I don’t think I have enough of a niche.
I’m tempted to start drafting an article on how to implement a fast templating language in Zig. After all, that’s what I’ve been doing with Deng, and it’d be good to share what I learned.
After several months, I’ve given LLM coding tools another try. Friends, it did not go well.
GenAI coding tools struggle to generate even syntactically valid code. When they do, they use deprecated APIs, or even non-existent ones. It is nigh impossible to have these tools generate code that even compiles.
And before I can get the output to a point where it is somewhat reasonable, I’m hitting the daily rate limits of these tools.
GenAI is so unbelievably bad that it is worse than useless. It is a waste of my time; I spend my time undoing the utter stupidity that these tools spit out, over and over again. It even fucks up existing code that was working perfectly fine. Over and over again, I have to rush to the agent’s STOP button to prevent it from bringing ruin to my codebase.
Genuine question: what the actual fuck.
I had expected there to have been progress in the last half year or so since I last used these tools. On the contrary; it seems like these tools have regressed.
Granted, I am using the free version of these tools. But free tiers, demos and trials are supposed to pull you in, right? I have just about zero interest in paying for these tools, given how much of a giant stinking pile of garbage the free versions are.
My experience with AI coding tools is vastly different from the advantages that many people on the Internet claim. I cannot reconcile these two worlds. Am I living in a parallel reality?
Entertainment:
-
No Other Land4 is harrowing.
-
A Bigger Splash5 is lovely intense, and you just know from the moment you see the swimming pool that something’ll happen with it.
I now would like to see more swimming pool movies. Swimming Pool,6 of course, is another great one.
-
I’ve completed my playthrough of all the games in the Blackwell series. Playing through them in chronological order shows how much better the games get over time, with better writing and storytelling, better character development, better voice acting, better visuals, and bigger emotional impact overall. I’ve said it before: anything developed or published by Wadjet Eye Games is worth it.
-
Avernum 4: Greed and Glory7 is a remarkably large game. I’m making my way through it slowly but surely.
Links:
-
William Gibson reads Neuromancer (abridged): Nice. This might make me get through Neuromancer after all.
-
Affinity - Professional Creative Software, Free for Everyone: So, all three Affinity products are combined into one and now free. What’s the catch?
-
How I built a Mechanical Calculator (William Gerhardinger): Wow!
Alasdair Beckett-King links:
Tech links:
-
Most of What We Call Progress (Yusuf Aytas)
-
The Vindication of Bubble Sort (Chris / Entropic Thoughts)
-
uv is the best thing to happen to the Python ecosystem in a decade (Dr. Emily L. Hunt)
-
Normalize Identifying Corporate Devices in Your Software (LGUG2Z)
-
Junior Dev Tip: "Scroll Up" (Alex Riviere): Simple but effective advice!
-
Stone Tools (Christopher Drum): “A blog about the productivity software of the 8/16-bit era.” Neat!
-
Taking a Step Back from Ruby / When Leadership Fails, Ecosystems Shrink (Tom Mango)
-
This is only correct if the returned
Setis not modified, Which it isn’t, in my case, and I’m using#freezeto ensure that. ↩︎ -
These two pieces of code aren’t strictly equivalent: the former evaluates to the original
@next_vertex_idx, while the latter evaluates to the new@next_vertex_idx. In my case, I didn’t use the return value, so that distinction didn’t matter. ↩︎ -
It’s not just Zig, of course! Go and Rust do something similar. ↩︎
-
No Other Land, directed by Yuval Abraham, Basel Adra, Hamdan Ballal and Rachel Szor (Yabayay Media, Antipode Films, 2024). ↩︎
-
A Bigger Splash, directed by Luca Guadagnino (Frenesy Film Company, Cota Film, StudioCanal, 2016). ↩︎
-
Swimming Pool, directed by François Ozon, written by François Ozon, Emmanuèle Bernheim and Sionann O’Neill (Fidélité Productions, France 2 Cinéma, Gimages, 2003). ↩︎
-
Avernum 4: Greed and Glory (Spiderweb Software, 2025), published by Spiderweb Software. ↩︎