Skip to content

Instantly share code, notes, and snippets.

@xentek
Created December 21, 2023 17:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xentek/7350823a2c9ae960300afc2eeb049895 to your computer and use it in GitHub Desktop.
Save xentek/7350823a2c9ae960300afc2eeb049895 to your computer and use it in GitHub Desktop.

Zig Notes

What is Zig?

Zig is a general-purpose programming language and toolchain for maintaining robust, optimal and reusable software.

Robust Behavior is correct even for edge cases such as out of memory.

Optimal

Write programs the best way they can behave and perform.

Reusable

The same code works in many environments which have different constraints.

Maintainable

Precisely communicate intent to the compiler and other programmers. The language imposes a low overhead to reading code and is resilient to changing requirements and environments.

Zig is strongly typed, but can be metaprogrammed (at compile time). Zig's compiler can cross-compile to any target LLVM supports (something that is tricky with C). Zig's compiler can be used to compile C/C++ programs. Zig does not depend on libc (like almost everything else does).

Zig is ambitious. It wants to become the heir to C’s longstanding reign as the go-to portable low-level language and as a standard to which other languages are compared. While Zig does compete with C: "we don't expect it to supplant C without a very long stretch of time where both languages have to coexist.”

Go is a better Java / C#, while Rust is not. The clarity that Go can bring to enterprise software development is without a doubt much more valuable than removing garbage collection at the cost of worsening the overall productivity.

Rust is a better C++, and even if you occasionally hear that Go is a better C, well, that’s just not the case. No language with a built-in garbage collector and runtime can be considered a C. And don’t be mistaken, Rust is a C++, not a C. If you want a better C, take a look at Zig.

Further Reading


Comptime and Metaprogramming

Zig places importance on the concept of whether an expression is known at compile-time. There are a few different places this concept is used, and these building blocks are used to keep the language small, readable, and powerful.

Compile-time, or comptime for short, opens the door to powerful metaprogramming techniques, not possible (or at least poorly approximated) in C/C++.

Zig's metaprogramming is driven by a few basic concepts:

  • Types are valid values at compile-time
  • Most runtime code will also work at compile-time
  • Struct field evaluation is compile-time duck-typing 🦆
  • The zig standard library gives you tools to perform compile-time reflection. 🤩

Further Reading


Memory Safety

Like Rust, C, and C++, Zig doesn’t use a garbage collector. To achieve memory safety like Rust, Zig comes with mechanisms that promote memory safety, such as:

  • Strict compile-time checks
  • Optional types to handle potentially null values
  • Explicit error handling with Error types
  • Enhanced memory allocation with built-in allocators

These mechanisms don’t severely affect coding in the language the way they do in Rust.

Further Reading


Compatibility with C/C++

Although Zig is independent of C, and, unlike most other languages, does not depend on libc, Zig acknowledges the importance of interacting with existing C code.

Zig natively supports C ABIs for extern things; which C ABI is used depends on the target you are compiling for (e.g. CPU architecture, operating system). This allows for near-seamless interoperation with code that was not written in Zig; the usage of C ABIs is standard amongst programming languages.

Zig internally does not use an ABI, meaning code should explicitly conform to a C ABI where reproducible and defined binary-level behaviour is needed.

An ABI (application binary interface) is a standard, pertaining to:

  • The in-memory layout of types (i.e. a type’s size, alignment, offsets, and the layouts of its fields)
  • The in-linker naming of symbols (e.g. name mangling)
  • The calling conventions of functions (i.e. how a function call works at a binary level)

Zig's direct import of C header files, use of slices for strings, standard library functions for null terminated strings, defer statements for resource cleanup, and pointer arithmetic with explicit conversion make it stand out compared to C, Rust, and Go.

Zig is also a C compiler.

This is thanks to Build Artifact Caching. Zig automatically parses the . d file uses a robust caching system to avoid duplicating work. Not only can Zig compile C code, but there is a very good reason to use Zig as a C compiler: Zig ships with libc.

Further Reading


Concurrency / Async

The async system in zig is conceptually similar to python with continuations, except 'low-level', and there's no function coloring. Under the hood it's similar to what Golang does, except Go has implicit yield points at curly brace closing, whereas you must explicitly perform yields (called suspends in zig) and resumes in zig.

Further Reading


Errors are values

An error set is like an enum. However, each error name across the entire compilation gets assigned an unsigned integer greater than 0.

An error type in Zig is separate from a normal Zig enum, and it’s what Rust would call a “C-style Enum”, it’s a series of named tags that each have no fields.

All error tags are implicitly also added to an anyerror automatic type by the compiler. You can have a function return a specific error type if you want to be able to exhaustively handle errors, OR you can have a function return an anyerror by omitting an error type on the left of the ! symbol (eg: !u64), in which case the function can return any error tag it wants, including that it can make up an error tag right there within the function definition.

Further Reading


Testing

Zig has first-class support for testing. zig test is a tool that creates and runs a test build. By default, it builds and runs an executable program using the default test runner provided by the Zig Standard Library as its main entry point. 🆒

Most of Zig's documentation of it's own language features is told using tests.

Further Reading


Embedded Programming

Zig can be used to create your own operating system or compile to microcontrollers. In other words, you can run it on BARE METAL with no operating system.

One of my big goals with Zig is to improve the embedded and OS development process. I hope you're as excited as I am about the potential here.

  • Andrew Kelly, Inventor of the Zig programming language

Zig feels like a good match for replacing C on microcontrollers because it permits “hold my beer” shenanigans and memory management is less of an issue. Zig metaprogramming also seems like a better match for these environments - think about how much nicer you could do stuff like qmk -, the Rust embedded stuff seems quite painful in comparison.

Further Reading


Build System

The Zig Build System provides a cross-platform, dependency-free way to declare the logic required to build a project. With this system, the logic to build a project is written in a build.zig file, using the Zig Build System API to declare and configure build artifacts and other tasks.

Zig supports generating code for all targets that LLVM supports. Zig's compiler has attracted contributions from some of LLVM's core maintainers.

Further Reading


Zig vs Go

Comparison Zig Go
Pros
Simplicity More explicit control over memory; no garbage collector. Garbage-collected approach simplifies memory management.
Performance Finer control over memory allocation can lead to optimized performance. Good performance with simpler concurrency model.
Interoperability Can directly call C functions with ease. Supports calling C functions but via 'cgo' which is less straightforward.
Cons
Ecosystem Growing community but less mature than Go's. Mature ecosystem with a larger community and extensive libraries.
Learning Curve Steeper learning curve due to manual memory management. Simpler for beginners with a robust standard library.
Tooling Developing toolset. Well-developed tooling and extensive IDE support.

Zig vs Rust

Comparison Zig Rust
Pros
Simplicity Simpler error handling and no hidden control flow. Borrow checker provides safety but with a steeper learning curve.
Performance Comparable performance; simpler model can ease optimization. High performance with guarantees of safety and concurrency.
Interoperability Seamless use of C libraries without a runtime. Good FFI but slightly more complex than Zig for C library usage.
Cons
Ecosystem Less developed ecosystem compared to Rust. Rapidly growing ecosystem, especially in areas like WebAssembly.
Learning Curve More straightforward but lacks some of Rust's advanced safety features. Rich type system and safety features but with a complex learning curve.
Tooling Less mature tooling compared to Rust. Advanced tooling, including Cargo and Clippy.

Comparison Zig C
Pros
Simplicity Modern features like generics; compatible with C. Simplicity and widespread use in education and industry.
Performance Offers better safety features while maintaining performance. Highly optimized performance; direct hardware access.
Interoperability Designed for interoperability with C. Extensive legacy codebases and wide application.
Cons
Ecosystem Emerging ecosystem compared to C's vast one. Vast, established ecosystem with extensive libraries.
Learning Curve Steeper learning curve for those accustomed to C. Ubiquitous and often considered a default learning language.
Tooling Developing toolset compared to C's extensive tools. Mature and extensive tooling and debugging utilities.

Zig vs C++

Comparison Zig C++
Pros
Simplicity Simpler syntax and build system. Complex features like object-oriented programming and templates.
Performance Predictable performance with straightforward memory management. Advanced optimizations possible with complex features.
Interoperability Good compatibility with C and potential with C++ codebases. Mature ecosystem, particularly in large-scale software and game development.
Cons
Ecosystem Less developed compared to C++'s extensive ecosystem. Extensive and mature ecosystem with a wide range of applications.
Learning Curve Easier to learn for certain tasks; lacks depth in some areas compared to C++. Complex but offers depth in programming concepts.
Tooling Less sophisticated tooling than C++. Advanced tooling, compilers, and debuggers developed over decades.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment