Note: Hello World, strings in Zig

I am doing the Exercism exercises for Zig and decided to document my progress since, with every exercise, I learn new and interesting information.

The first exercise is doing a “Hello World” and the end solution is simple:

pub fn hello() []const u8 {
    return "Hello, World!";
}

The interesting part is that Zig represents string literals as []const u8, which is an array of bytes.

const foo = "Hello" is (almost) the same as const foo = [_]u8{ 'H', 'e', 'l', 'l', 'o' }; Let’s break it down:

  • const means it’s a constant value or immutable.
  • [_]u8 means it’s an array of bytes.
  • The compiler will infer the [_] to [5].

Where the string uses double quotes (“H”), and the individual characters (‘H’) use single quotes.

But there is more because a string also contains a sentinel value. A sentinel value is something that indicates the end of a sequence. A popular choice of a sentinel value is the value 0, also called the null character.

Zig supports sentinel-terminated arrays, slices, and pointers:

//.    This is taken from Ziglings, exercise 76.
//     const a: [4:0]u32       =  [4:0]u32{1, 2, 3, 4};
//     const b: [:0]const u32  = &[4:0]u32{1, 2, 3, 4};

Array a stores five values, the last of which is a 0. Array b is only allowed to point to zero-terminated arrays.

Now we can determine the actual type of a string in Zig:

@TypeOf("foo") == *const [3:0]u8

Translated to English, a string is a “constant pointer to a null-terminated fixed-size array of u8”.

Now, why would you still have a 0 at the end when you know the size of the array? That’s because Zig strings are compatible with C strings, which are also null-terminated.

If you want to learn more about strings, I can recommend the Zig / Strings in 5 minutes article.

Shorter feedback loops with Elixir tests Kaizen Principle