Hello Zig: intuitive syntax matters

Zig is apparently aimed at C programmers, which implies C++ programmers may also be interested. With so many ‘next big thing’ tools out there, one can only find so much time for exploring; we’ve got things to do and lives to live.

For this reason, the intuitiveness of a language is important. I’m a big fan of the principle of least surprise. Something simple should ideally be guessable.

The tool also needs to fill three sets of needs:

  • solves enough problems to make it worth learning
  • practically of usage
  • quick to use for the domain it targets

Zig claims to solve a lot of problems that matter to me as a C++ engineer1 with some dedication to to making it practical to integrate into existing projects2, so the focus here is on the latter. Python is a great example of all this: simple programs are simple to write, setup is minimal, doing something useful with syntax that even non-programmers can somewhat understand.

Zig interests me, but I’m interested in a lot. Let’s try reading some:

const std = @import("std");
const zag = @import("zag");
pub fn main() !void {
// Prints to stderr, ignoring potential errors.
std.debug.print("All your {s} are belong to us.\n", .{"codebase"});
try zag.bufferedPrint();
}

This is the “hello world” program produced by zig init. Here are my guesses:

  • const X = @import("Y"): imports some kind of module
  • pub: affects the visibility of code outside the module
  • fn main(): declares a function called main that is the entry point
  • { ... }: function body
  • !void: unclear what ! means, but void implies returning nothing.
  • //: a comment
  • std.debug.print: a function from the imported standard library
  • "All your {s} are belong to us.\n“: a format string literal
  • .{"codebase"}: unusual syntax, “codebase” will replace “{s}”
  • try zag.bufferedPrint(): might throw or error, handling unclear

Now let’s see how close I was. This highlights another important factor: how do I ask questions about it? Searchability online matters and if one doesn’t know the technical name for a concept3, it’s hard to get started.

Thankfully, I quick search for “zig import syntax” lead me to documentation that answered almost all my questions thus far. My guesses were mostly correct and I learnt more about the language along the way:

  • comptime allows one to request something at compile-time
  • @import uses comptime for its argument
  • The @` prefix means “built-in function”
  • Zig doesn’t have a special string type, it uses arrays
  • Format strings are comptime
  • .{} means “anonymous tuple”
  • ! in a return type means “this or an error”
  • try here means “the result of this or return an error”

So for this small code-snippet, I’d say it’s passed the litmus test.

  1. It’s a huge part of what motivated me to write this. For example:

    – Hidden memory allocations are rife in C++ and they bother me daily.
    – Pre-processing is thorny and fragile: better solutions exist now.
    – Compile-time support may eliminate some obtuse corners of C++. ↩︎
  2. Support for building and linking against existing C++ projects is going to make this a lot easier to pitch at work on existing projects. ↩︎
  3. SFINAE in C++ is a good example: how on Earth is someone supposed to guess that name? They’d have to already understand it to do so ↩︎