Comment by messe
> Whether the implementation of a function performs IO is in principle an implementation detail that can change in the future.
I think that's where your perspective differs from Zig developers.
Performing IO, in my opinion, is categorically not an implementation detail. In the same way that heap allocation is not an implementation detail in idiomatic Zig.
I don't want to find out my math library is caching results on disk, or allocating megabytes to memoize. I want to know what functions I can use in a freestanding environment, or somewhere resource constrained.
> Performing IO, in my opinion, is categorically not an implementation detail. In the same way that heap allocation is not an implementation detail in idiomatic Zig.
It seems you two are coming at this from opposing perspectives. From the perspective of a library author, Zig makes IO an implementation detail, which is great for portability. It lets library authors freely use IO abstractions if it makes sense for their problem.
This lets you, as an application developer, decide the concrete details of how such libraries behave. Don't want your math library to cache to disk? Give it an allocating writer[0] instead of a file writer. Want to use an library with async functionality on an embedded system without multi threading? Pass it a single threaded io[1] runtime instance, implement the io interface yourself as is best for your target.
Of course someone has to decide implementation details. The choices made in designing Zig tend to focus on giving library authors useful abstractions thst give application authors meaningful control over important decisions for their application.
[0] https://ziglang.org/documentation/master/std/#std.Io.Writer....
[1] https://ziglang.org/documentation/master/std/#std.Io.Threade...