All notes tagged with zig.

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.

March 25, 2024

zig testing

Test selection with Zig

With Zig, I usually run zig build test to run all the tests. However, sometimes, I need to run a single test, and that option is not available through the build command.

In this case, I learned you can use the zig test command along with the --test-filter option.

For example, to test a single test named “lexer initialization” located in src/lexer/lexer.zig, you can run zig test --test-filter “lexer initialization” src/lexer/lexer.zig. It’s worth noting that the test filter doesn’t have to be the full name of the test to be able to find it.

December 13, 2022


Easily install Zig with zigup

I used to manage my Zig installation by installing the binary and copying to my path. Not too hard, but now there is even an easier way by using zigup.

To install zig, it enables you to simply type zigup master

I would recommend to get the latest binary from the Github releases page. Or if you already have Zig, install it from source:

# Install the binary
git clone [email protected]:marler8997/zigup.git
cd zigup
zig build -Dfetch
cp zig-out/bin/zigup ~/.local/bin/

November 24, 2022


Zig types explained in Ziglings

I have been tinkering with Zig lately and to get a grasp on the language I have been using the excellent Ziglings quizes.

In Quiz #58 there is a great comment which lists the different types for Zig:

// We've absorbed a lot of information about the variations of types
// we can use in Zig. Roughly, in order we have:
//                          u8  single item
//                         *u8  single-item pointer
//                        []u8  slice (size known at runtime)
//                       [5]u8  array of 5 u8s
//                       [*]u8  many-item pointer (zero or more)
//                 enum {a, b}  set of unique values a and b
//                error {e, f}  set of unique error values e and f
//      struct {y: u8, z: i32}  group of values y and z
// union(enum) {a: u8, b: i32}  single value either u8 or i32
// Values of any of the above types can be assigned as "var" or "const"
// to allow or disallow changes (mutability) via the assigned name:
//     const a: u8 = 5; // immutable
//       var b: u8 = 5; //   mutable
// We can also make error unions or optional types from any of
// the above:
//     var a: E!u8 = 5; // can be u8 or error from set E
//     var b: ?u8 = 5;  // can be u8 or null