Zig First Impressions from a JS Dev

Anonymous Duck - Aug 24 - - Dev Community

I've been learning zig for my game development project, read more about it here. Those are my initial (mostly positive) impressions of the language, coming from a mostly JS/TS recent experience.

Error handling

Errors are values - It's quite a popular opinion at this point that exceptions aren't the best. They create a hidden control flow, and in JavaScript they can't even be declared; which makes your applications much more unstable.

Zig uses error enums and nice syntactical sugar for easy and fun error handling. For example :

fn failingFunction() error{MyError}!void {
    return error.MyError;
}

pub fn main() !void {
    try failingFunction();
}
Enter fullscreen mode Exit fullscreen mode

In the code above we declare an error MyError (This can also be done separately) and return it.
The try means "if this returns an error, return it here" as in:

failingFunction() catch |err| return err;
Enter fullscreen mode Exit fullscreen mode

I believe this approach is a great combination and saves us from the endless if (err != nil) in Go land.

Other highlights:

  • Errors are explicit, all types have to be declared and handled
  • Handling is done right then and there, not on the block level
  • Thanks to payload capturing, errors are typed correctly and autocompeleted, making it easy to use something like a switch expression.

The !void syntax - ! is used to create a union between the return type and the error types. Zig supports not adding any errors prior to the !, which is supposed to create a union of all the errors that you actually return from the function.

In practice, I find this syntax unhelpful. At least with my IDE experience I don't get any intellisense in this case, and it makes the function less clear. Just tell me what you are gonna return!
I only see it being useful on the main() function.

Payload capturing

You know how in TS you might have a type like number | undefined? You might use an if or some logic to narrow down the type to what you need, and TS automatically displays the new type correctly.
While it's easy, there are problems with this approach:

  • If types can change throughout a function, it's harder to follow
  • In some cases you still have to do a cast

In Zig, you do this with "Payload Capturing". You can "capture" aka create a new immutable variable with the resulting type. For example:

const maybe_num: ?usize = 10; // `?` Means it can be `null`

if (maybe_num) |num| {
    // Use num
}
Enter fullscreen mode Exit fullscreen mode

It's very clear what's happening! Moreover, the variable is immutable, but if you really need to change it, you can capture a pointer to the value instead.

It's also worth mentioning that this mechanism can be used throughout the language, including: for, switch, catch, etc.

Comptime shenanigans

Admittedly I didn't yet grasp the full possibilities of comptime. But in short, you can run regular code during compilation. You may create whole functions that are only used during this time, and can return compilation errors if necessary.

It suits Zig quite well, because it's a very malleable language. Even types are values, meaning you can create, change, and get information about types (Especially in comptime).

A basic example of this from the Zig Guide:

const a = 5; // When a number type isn't specified, it defaults to comptime_int
const b: if (a < 10) f32 else i32 = 5;
// b: f32 after compilation
Enter fullscreen mode Exit fullscreen mode

Editor experience

I'm using VSCode with the official Zig plugin (which uses zls). The intellisense and errors I see in the editor leave much to be desired.

"detectable illegal behavior" aka illegal things that will result in a compilation error aren't typically displayed in the editor. For example:

const nums = [3]u8{ 2, 1, 3 };
_ = nums[4]; // Index out of bounds error
Enter fullscreen mode Exit fullscreen mode

I'm on the 0.14 (dev) master branch version, if it's supposed to work let me know in the comments!

EDIT:
I was able to enable this type of error checking in VSCode by enabling the "Enable Build On Save" option under the zig extension settings.
Which is exactly what it sounds like, saving the file will rebuild the app and show any errors resulting from compilation on the correct lines. 🤦

. .
Terabox Video Player