I tried the Hello World example in the online tool. Then I removed the first try keyword, and got very strange error.
const std = @import("std");
pub fn main() !void {
var stdout_file = /* try */ std.io.getStdOut(); // <<-- here "try" was removed just to see what happens
try stdout_file.write("Hello, world!\n");
}
results in:
/home/runner/.code.tio:8:20: error: type 'WindowsGetStdHandleErrs!File' does not support field access
/srv/wrappers/zig: line 4: ./.bin.tio: No such file or directory
which is doubly strange, as if it tries to use a Win32 function under an Unix OS.
Removing the second (and only the second) try results in error:
/home/runner/.code.tio:5:22: error: expression value is ignored
Not especially helpful, either. Imagine a novice, he would be completely lost. The compiler should give a hint what one could do there.
And a note: the simpler Hello World example should be the first one. The one with "try"s has good chance to scare away newcomers.
That funny !void deserves a comment.
A suggestion: add function echo, which prints to stdout, is always available, doesn't use namespacing or errors or any other ceremony.
Nim language has such function and it serves it well.
Hello World example then could be just:
pub fn main() void {
echo("Hello, world!\n");
}
Or they could use @import("std").debug.warn. I don't think we should pollute the global namespace with stuff from std.
Fun fact, the only reason getStdOut can fail is due to it being a cross platform abstraction that includes windows. So it actually makes sense that the error set has windows in the name.
@PavelVozenilek
Writing to stdout can error, so we want to have proper error handling for it like any other function. Polluting the global namespace is also a bad idea.
const std = @import("std");
pub fn main() !void {
var stdout_file = try std.io.getStdOut();
/* try */ stdout_file.write("Hello, world!\n"); // missing try
}
should result in error: uncaught exception (or similar) rather than error: expression value is ignored.
@phase: use case for "frictionless" echo are beginners, people who learn by small examples. They do not want imports, namespaces or errors just to print out something. They are learning, not building nuclear-powerplant-grade software.
If they get impression of something overcomplicated, they will flee away.
@PavelVozenilek echo might be frictionless for beginners, but it adds friction for the experienced (anyone who knows how to import). Zig already have plenty keywords that pollute our global namespace. The one I find the most annoying is type since I want to use type as a variable/field often. @"type" only partly solves this, as it allows me to have fields called @"type", but this doesn't work because shadowing is not allowed:
const @"type" = 2; // error: declaration shadows type 'type'
const A = struct {
// error: declaration shadows type 'type'
fn @"type"() u64 {
return 2;
}
};
test "" {
const a = @"type";
const b = A.@"type"();
}
I've come to accept this, as type is a powerful comptime concept that I also use a lot. Its benefits outshine its negatives.
There is also the fact that echo would have to be implemented somewhere. One of Zig's goals is that the language doesn't depend on the standard library. So where should the implementation of echo be? builtin.zig? And what about "Only one obvious way to do things."? Should people use debug.warn or echo?
Also, here is a simple "Hello World" program in Zig, that doesn't require import:
comptime {
@compileLog("Hello World!\n");
}
I would argue, that this is simpler than declaring main and calling echo. In main, beginners would ask what does pub fn main() void mean, and then the teacher would either be "Don't worry about it" or "It's a function declaration 'insert explanation here'". comptime is easier to explain. "comptime tells Zig to execute the block when you call zig build-exe someprogram.zig", which is not a lie, but hides some truth.
For echo, what do we actually gain? Anyone who has programmed in any language before knows of the concept of importing code in some sense. Which language doesn't have this? This only benefits new programmers. Programmers, who should probably start with Python if they want to print things after 2 seconds of programming (This is not to bash on Python. Its goal is to write small amounts of code that does a lot).
@Hejsil: echo would be useful for beginners and for ad-hoc debugging. Not situations where complexity of the libraries is appreciated. Experienced programmer wouldn't build application from echo, and if he does, he deserves it.
Current io hierarchies remind me iostreams catastrophe of C++. Grandiose design which fills a book and still no one understands it. Who needs this? It could be specialised library mentioned in an appendix. Exposing it in Hello World is unwise.
echo is rejected. case closed
anyerror!void is the recommended return type of main, and is more clear than !void
Most helpful comment
echois rejected. case closed