Zig NEWS

Cover image for Where is print() in Zig?
Loris Cro
Loris Cro

Posted on • Updated on

Where is print() in Zig?

Zig has no built-in print function or statement.
If you want to print something quickly, you can use std.debug.print:

const std = @import("std");

pub fn main() void {
   std.debug.print("Hello World!", .{});
}
Enter fullscreen mode Exit fullscreen mode

Why is there no built-in function like C's printf?

One answer is that, unlike C, Zig doesn't need to special-case the printing function. In C, printf could not be implemented as a normal function without losing its special compile-time checks (i.e., the compiler can check that the number of arguments passed to printf matches the number of % placeholders in the format string).

In Zig all of that can be implemented in userland using comptime checks.

Another reason why Zig has no built-in print function is that printing is less obvious than what some other languages would lead you to believe.

When printing becomes actually important

When you are just printing a debug line to the console, you don't care about handling error conditions, but sometimes printing to the terminal is the core functionality of your application and at that point, to write a robust tool, you will need to design for failure.

On top of that there might be performance implications related to buffering, or you might be sharing the output stream with other threads, at which point a lock might (or might not) be necessary to ensure that the printed information keeps making sense.

Earlier we saw std.debug.print and that function made some choices for us:

  • it prints to stderr
  • it has a lock in case you have multiple threads
  • it does not buffer
  • errors get discarded

This is its implementation (from the stdlib):

pub fn print(comptime fmt: []const u8, args: anytype) void {
    const held = stderr_mutex.acquire();
    defer held.release();
    const stderr = io.getStdErr().writer();
    nosuspend stderr.print(fmt, args) catch return;
}
Enter fullscreen mode Exit fullscreen mode

Printing more reliably

To print in a more reliable way, you can use std.log, which also works as a more complete logging system with support for different scopes and levels. You can read more about it in the stdlib.

Printing to stdout

If you want to have direct access to stdout, you can use std.io.getStdOut() and from there use the writer interface to print, just like the code above does with stderr. At that point it will be up to you if you want to have buffering (using a std.io.BufferedWriter) or a lock, and you will also have to decide what to do with errors.

Watch the talk

If you want to listen to me give a full talk just on this topic, here you go :^)

Top comments (2)

Collapse
 
stas profile image
Stas Miasnikoŭ

In C, printf could not be implemented as a normal function

Not true. Checks are not necessary, just gotta be careful.

Collapse
 
wrp profile image
William Pursell

I am new to Zig and new to this forum, but surprised to see no comments on this. As a long-time C programmer, I was very surprised that stdout (eg, std.io.getStdOut().writer()) is not buffered by default. After thinking about it for a few moments, I realize that this is a faulty mindset on my part caused by conditioning. Over the past few decades, the amount of confusion that has been caused by the different treatment of buffering in stdout vs. stderr has probably led to 100s of thousands of lost hours. (Whether those hours are "lost" or are worthwhile educational experiences is a different question!) Making this very explicit is an aspect of the Zig philosophy that I find very refreshing. Great talk!