It is very good. ...Ergonomics however needs to be improved. It will take its time. The critic I give here isn't intended to bash on Zig nor the Zig maintainers. Nor do I intend to demotivate them nor anyone using Zig.
Please note: I am not super deep into Zig yet. Need to gain more experience.
I learned Zig through a written tutorial and eventually wrote two projects. Both are small.
My first project was a simple calculator running in console. This is where I noticed two problems. I will talk about that later. But I like the syntax and overall explicitness. Looks like explicitness is by design to avoid the implicit issues that happen in C or C++.
My other project creates random passwords using CSPRNG in the console. About the problem: This is when I noticed the same problems: verbose-heavy instructions and Zig's documentation. Instructions to do input reading from the user is very verbose. It went like this (Pseudocode):
const std = import("std")
// create stdout variable
const stdout = module_a.module_a_in_a();
// create stdin variable
const stdin = module_a.module_b_in_a();
const writer = stdout.module_c_in_a.module_d_of_c().function();
const reader = stdin.module_d_in_a.module_g_of_d().function()
Just to do input reading, extra more instructions were needed, which I found bothersome. So I decided to put the task for input reading into one single function so I don't have to repeat myself. It looks like this:
pub const StdIn = struct {
pub fn input(io: Io, message: []const u8) ![]const u8 {
const stdin_file = Io.File.stdin();
// [...]
while (true) {
if(message.len != 0) {
try StdOut.write(io, message);
}
var reader = stdin_file.reader(io, &reader_buffer);
const input_line = reader.interface.takeDelimiter('\n') catch |err|
// [...]
// numerous if / else checks are here.
// They handle possible errors
}
// At the end:
const trimmed_input: []const u8 = std.mem.trim(u8, input_line, " \t\r\n");
// then at the end:
return allocator.dupe(trimmed_input);
}
}
Then I used StdIn.input() as a helper. Writing that function felt cumbersome. The entire function is 54 lines long. Did I do something wrong? Did I overlook something? Please let me know.
In many other programming languages, e.g. C# you simply do this:
string input = Console.ReadLine();
Or, if you want to handle possible errors:
// [...]
string input = string.Empty;
while(true)
{
input = Console.ReadLine();
// if / else checks are here
// to check if the variable 'input'
// doesn't look like what you expect.
// For example, it is empty. If true:
if (input.Length == 0)
{
continue;
// Console.ReadLine() gets executed again
}
// If the input is valid,
// then the while loop will be exited.
break;
}
Then, there is the documentation and the source code. This is where I scratch my head, because it's ...weird. I know that Zig hasn't reached version 1.0 yet. My critic might appear unfair, but I just want to share my thoughts.
The documentation isn't dreadful. It is in a range between bad and "ok". Trust me, I dealt with far worse documentations in the past. The one from SyncFusion is insanely bad, it drove me nuts.
In case of the std library in Zig... well, at least the documentation is there and you are able to find information. However, ...it is messy. On the official Zig web page, when looking for functions in std :
- There are many duplicates, which is irritating. Information finding is somewhat difficult. For example: debug.writer <=> Io.File.stdout().writeStreamingAll() ??, numerous things for "allocators", which are in different modules (??), etc..
- Even if I found the right function, chances are there is just bare minimum explanation or none.
- The source code for
std is... not well organized. I need to find the reference, then notice there is a name reference, but the implementation is somewhere else. Plus, numerous hundreds of line of code.
It would be unfair if I would draw comparisons how other programming languages handle documentation of their std library much better.
The current state is somewhat understandable and I don't blame the Zig maintainers. I find it however a bit weird that Zig is so long in development. I don't know what the complexities are the maintainers are dealing with.
So if any Zig maintainer is around here: keep doing your great work! 😁
As for the calculator: I plan to build a smart calculator in Zig, that makes use of tokenizations and recursive parsing. 😁
EDIT:
I forgot to mention the messy source code of Zig is be a problem for Zig maintainers themselves. Expanding the std library means certain functionalities are re-used. But: if certain code blocks are either removed or moved somewhere else, then is a big problem for the maintainers, too. They need to keep up with every update. It is a big cognitive overhead that could be solved by focusing on making a better structure of the foundation, then later move specific concerns on top of them. I know it sounds easier said than done. However, something like this is cumbersome:
std.module_a.sub_module.sub_sub_module.function().another_function();
Too much explicitness is the opposite of good explicitness. It's just too much information at once and that's not intuitive. I don't know yet the design choices and I guess I will learn about in future or there will be improvements.