# Hello World

> Your first Zig program, and why main now takes an argument.

Here is a complete Zig program. Press **Run**; it executes in your browser as
WebAssembly.

```zig
const std = @import("std");

pub fn main(init: std.process.Init) !void {
    try std.Io.File.stdout().writeStreamingAll(init.io, "Hello, World!\n");
}
```

*Runnable: compiled to WebAssembly and executed by CI against Zig master. (`01-getting-started.hello-world`)*

## Why does `main` take a parameter?

If you have seen Zig before, you probably expect `pub fn main() !void`. On
current Zig master, `main` receives a `std.process.Init`:

```zig
pub fn main(init: std.process.Init) !void
```

That `init` carries an **`Io` instance**, `init.io`. This is the same idea as
`Allocator`, applied to I/O: just as Zig never allocates behind your back, it
now never blocks behind your back either. Any function that touches the
filesystem, network, or clock takes an `Io` explicitly, so the caller decides
whether that work is threaded, evented, or something else entirely.

The practical consequence is that you cannot reach for a global `stdout`. You
must be handed the capability to write.

## Buffering, and the `flush` you must not forget

`writeStreamingAll` is fine for a single fixed string, but real programs format
output. For that you want a buffered writer:

```zig
const std = @import("std");

pub fn main(init: std.process.Init) !void {
    var buf: [1024]u8 = undefined;
    var file_writer = std.Io.File.stdout().writerStreaming(init.io, &buf);
    const out = &file_writer.interface;

    try out.print("{s} v{d}.{d}\n", .{ "zig", 0, 16 });
    for (0..3) |i| try out.print("  line {d}\n", .{i});

    // Nothing is written until the buffer is drained.
    try out.flush();
}
```

*Runnable: compiled to WebAssembly and executed by CI against Zig master. (`01-getting-started.buffered-stdout`)*

Since Zig 0.15 (the release nicknamed *"writergate"*), writers are buffered and
the buffer is part of the **interface**, not the implementation. You supply the
memory, which means no hidden allocation.

The tradeoff is that **nothing is written until you `flush`**. Delete the
`try out.flush()` line above, press Run, and you will get no output at all. Try
it: click **Edit**, remove the line, and Run again.

<aside>

**A note on `std.debug.print`**: it writes to stderr, is unbuffered, and needs
no `Io`. That makes it convenient for quick debugging, but it is deliberately
not the tool for program output.

</aside>
