I can’t recall who it was that said a language may create friction on certain usage to nudge the coders into a specific paradigm. Zig is my favorite language in that it promotes the programming style I really like, in such a natural way that you feel friction if you don’t do it that way.
I don’t have a clear list yet, but I can jot something down about the most obvious design philosophy of making dependencies explicit, as the OP also fell in love with.
Context switch is hard, both for the machine and the human. In a typical non-Zig program, your app talks back and forth with different objects and concerns. You have to trace through the call chain to understand what is happening. And anything could happen in between, with all sorts of possible exceptions.
In Zig, this style gets frustrating faster than any other language. If you allocate memory here and there, if you litter IO here and there, your code gets stinky, and the allocator and io buddies piggyback around on almost all your functions. It’s similar to the so-called colored function problem on other forums.
I don’t think it’s a problem. I think it’s a hint and a good friction. I promote a Sandwich Pattern. Instead of doing things just in time, you schedule in your mind. You think of what you will use later, and fetch them in one bulk stage. You think of what you can put off, and buffer those calls until you definitely need them. The end result is a clear prepare-grudge-commit workflow, and each stage takes a neat handful of dependencies.
For example, an array list of managed objects requires complicated cleanup:
defer {
for (my_list) |x| gpa.free(x);
my_list.deinit(gpa);
}
The need for the defer is eliminated if you used an arena.
You may ask: what if my resource has to be closed, let’s say, a list of File handles?
Use pools. Putting homogenous resources together.
There are many more opportunities. I won’t show off too many cases. There are many more smart people around, but I do think, that your smartness only comes into play when you see a problem. Zig presents that problem in a good way, and I sincerely hope that it insists on that philosophy.
For example, I had a use case that had to wiggle with three buffers, with the last one getting reused in a loop.
My first version had three defer’s, naively.
Then, I realized I could allocate all of them in an amalgamate buffer, and call resize if I need to.
The end result is shorter, cleaner code, with less intrusion from memory management.
I don’t hide the complexity of memory management. I push it physically away into another block of code. I loved reading such code, and I assume machines also like to.
This is not premature optimization. This is something that grows in me as a default.
(PS: AI slop has made me hairy. Every time I say “it is not… it is” I feel I’m talking like an LLM
)
The pattern is not news to experienced systems programmers, and often seen in well optimized C code, but it is easier to write spaghetti in C/C++. In Zig, it’s grinding to write spaghetti. And, you know,
The three great virtues of a programmer: laziness, impatience, and hubris. — Larry Wall
A lazy programmer then falls naturally for the Sandwich Pattern.
It is extremely frustrating to optimize non-sandwich code, too. I didn’t realize how much it hurts until getting bitten in my career work. My main programming language is Python. I always thought: hey, this is job, and who cares about performance in Python? But it bit when when I had to optimize for GIL, IO, and memory usage. Yes, you heard that. OOM is my daily cuisine as a data engineer. So I adopted the same idea of staged processing. I push code into a sandwich structure, getting as much as I can on the entrance IO, doing as much as I can in the middle, and delaying as much as I can to the final IO stage. For IO, I marshal only the minimal required piece to a thread pool, so the loop runs pretty focused. This way, my code runs faster than anyone else’s, with decent dev efficiency, without RIIR.
So, explicitness, at start, makes your code longer, even verbose. But it is turning the symptom out, it is not the disease. When you see longer code and feel uneasy, there is nothing wrong in the thought. You should keep being slothful, just in a different direction: how can you structure the code in good sanity, when you assert explicitness? The question drives me incredibly well into a better design, always.