Hello World

hello.zig

  1. const std = @import("std");
  2. pub fn main() !void {
  3. const stdout = std.io.getStdOut().writer();
  4. try stdout.print("Hello, {}!\n", .{"world"});
  5. }
  1. $ zig build-exe hello.zig
  2. $ ./hello
  3. Hello, world!

The Zig code sample above demonstrates one way to create a program that will output Hello, world!.

The code sample shows the contents of a file named hello.zig. Files storing Zig source code are UTF-8 encoded text files. The files storing Zig source code are usually named with the .zig extension.

Following the hello.zig Zig code sample, the Zig Build System is used to build an executable program from the hello.zig source code. Then, the hello program is executed showing its output Hello, world!. The lines beginning with $ represent command line prompts and a command. Everything else is program output.

The code sample begins by adding Zig’s Standard Library to the build using the @import builtin function. The @import("std") function call creates a structure to represent the Standard Library. The code then makes a top-level declaration of a constant identifier, named std, for easy access to Zig’s standard library.

Next, a public function, pub fn, named main is declared. The main function is necessary because it tells the Zig compiler where the start of the program exists. Programs designed to be executed will need a pub fn main function. For more advanced use cases, Zig offers other features to inform the compiler where the start of the program exists. Libraries, on the other hand, do not need a main function because library code is usually called by other programs.

A function is a block of any number of statements and expressions that, as a whole, perform a task. Functions may or may not return data after they are done performing their task. If a function cannot perform its task, it might return an error. Zig makes all of this explicit.

In the hello.zig code sample, the main function is declared with the !void return type. This return type is known as an Error Union Type. This syntax tells the Zig compiler that the function will either return an error or a value. An error union type combines an Error Set Type and a Primitive Type. The full form of an error union type is <error set type>``!``<primitive type>. In the code sample, the error set type is not explicitly written on the left side of the ! operator. When written this way, the error set type is a special kind of error union type that has an inferred error set type. The void after the ! operator tells the compiler that the function will not return a value under normal circumstances (i.e. no errors occur).

Note to experienced programmers: Zig also has the boolean operator !a where a is a value of type bool. Error union types contain the name of the type in the syntax: !``<primitive type>.

In Zig, a function’s block of statements and expressions are surrounded by { and } curly-braces. Inside of the main function are expressions that perform the task of outputting Hello, world! to standard output.

First, a constant identifier, stdout, is initialized to represent standard output’s writer. Then, the program tries to print the Hello, world! message to standard output.

Functions sometimes need information to perform their task. In Zig, information is passed to functions between open ( and close ) parenthesis placed after the function’s name. This information is also known as arguments. When there are multiple arguments passed to a function, they are separated by commas ,.

The two arguments passed to the stdout.print() function, "Hello, {}!\n" and .{"world"}, are evaluated at compile-time. The code sample is purposely written to show how to perform string substitution in the print function. The curly-braces inside of the first argument are substituted with the compile-time known value inside of the second argument (known as an anonymous struct literal). The \n inside of the double-quotes of the first argument is the escape sequence for the newline character. The try expression evaluates the result of stdout.print. If the result is an error, then the try expression will return from main with the error. Otherwise, the program will continue. In this case, there are no more statements or expressions left to execute in the main function, so the program exits.

In Zig, the standard output writer’s print function is allowed to fail because it is actually a function defined as part of a generic Writer. Consider a generic Writer that represents writing data to a file. When the disk is full, a write to the file will fail. However, we typically do not expect writing text to the standard output to fail. To avoid having to handle the failure case of printing to standard output, you can use alternate functions: the functions in std.log for proper logging or the std.debug.print function. This documentation will use the latter option to print to standard error (stderr) and silently return on failure. The next code sample, hello_again.zig demonstrates the use of std.debug.print.

hello_again.zig

  1. const print = @import("std").debug.print;
  2. pub fn main() void {
  3. print("Hello, world!\n", .{});
  4. }
  1. $ zig build-exe hello_again.zig
  2. $ ./hello_again
  3. Hello, world!

Note that you can leave off the ! from the return type because std.debug.print cannot fail.

See also: