const std = @import("std");
pub fn main() !void {
// If this program is run without stdout attached, exit with an error.
var stdout_file = try std.io.getStdOut();
const stdout = &stdout_file.outStream().stream;
// If this program encounters pipe failure when printing to stdout, exit
// with an error.
try stdout.print("number: {}\n", i32(1234));
} const print = @import("std").print;
pub fn main() void {
print("Hello, world!\n");
}
Why does it have to be more complex than warn?
You admit the added complexity yourself by using warn instead of print in the parent wiki page. pub fn warn(comptime fmt: []const u8, args: ...) void {
const held = stderr_mutex.acquire();
defer held.release();
const stderr = getStderrStream() catch return;
stderr.print(fmt, args) catch return;
}
The tradeoff, however, is that when the function returns, it is not guaranteed that the warning message made it successfully to stderr.This tradeoff is not appropriate for stdout.
Also the decision to use the mutex is not appropriate for stdout. The application may be single-threaded, or have its own synchronization strategy that makes the mutex redundant.
Zig is optimal.
This trade-off is not self-evidently correct... it's easily boiled down to personal preference. Consistency would be nicer. Zig is not "optimal" just because someone says it.
So, suppose warn() fails. What can you do about it - try to print a warning that you can't print warnings?
If you want something different, use a library or some other parts of the stdlib. Making that super common use case painful is not obviously a good decision.
The super common use case is std.debug.warn, not printing to stdout.
I would actually even argue that the meaning of "print" as printing to stdout by default is an unfortunate historical artifact. For the kind of stuff print is usually used by most of the code, it really should go to stderr, and "print" kinda implies some kind of logging IMO.
From that perspective, my suggestion would be to add a no-failure @import("std").debug.print that is an alias for warn. I don't think it's likely that breaking the established convention of print-defaults-to-stdout would cause issues in practice - in programs where this matter (like cat), the developer will quickly discover the issue the moment they try using it in a pipeline. And for programs where it doesn't, defaulting to stderr is actually the right thing.
But if you'd rather not break the convention, how about adding debug.log that is an alias for debug.warn? Or debug.say, or something like it.
stderr is the one that is not likely to be redirected somewhere that might fail - that's the whole point of keeping it distinct from stdout! And if it does get redirected, than the person that is requesting redirection is responsible for ensuring lack of failures in that channel.
I think you're approaching this from the perspective of stdout as a place for diagnostic output. It's not - it's a place for actual output (i.e. a function of program's input - the useful result of its operation). Yes, in practice, people routinely use it for diagnostics, but that's exactly the problem that Zig is trying to fix here by being opinionated about it, so far as I can tell.
pub fn main() !void {
try print(...)
}When developing, "print" is more commonly used as an aid for the developer. Most "print" messages should either be removed or outsourced to a library when the program nears completion. "warn" fills a similar purpose as "print".
If you really want "print", a small function that writes to stdout is quick to write.
If you classify all C-programs by what output they use (multiple counts allowed), printf/puts shows up with the highest percentage long before ncurses, X or anything else.
Quoting the docs linked above:
> Usually you don't want to write to stdout. You want to write to stderr. And you don't care if it fails. It's more like a warning message that you want to emit. For that you can use a simpler API:
const warn = @import("std").debug.warn;
pub fn main() void {
warn("Hello, world!\n");
}A while ago, I tried to figure how how to do the equivalent of C's
int n = 42;
printf("n = %d\n", n);
I was unable to find a straightforward way to do that. (Formatted output to stderr, on the other hand, is easy.) I submitted a bug report and haven't gotten a response.