My views on Zig (2022)
Zig is a general-purpose programming language. It is simple and does not have any hidden control flow or allocations.
The language is clear, straight-forward, and readable.
Zig directly competes with C and will be a better alternative for C in the future.
Things that I love about ziglang:
Simple language
Building a simple language is easier said than done. Programmers need rich features in a programming language, but when the programming language supports more features, it becomes sluggish and bloated.
For example, A simple hello-world program in zig will look like this.
// hello.zig
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
try stdout.print("Hello!, {s}\n", .{"world"});
}
In the first line, we are importing the std
library (curious why we have @
before import
check here). We import the std
library and assign it to std
using the const
keyword.
Next, we define the main
function. As in other languages, the main specifies the zig compiler where to start the program execution. The function definition commences with the pub fn
keyword. As you might have guessed, pub fn
means public function.
Note: The
pub
specifier exports the function.
Then we have the function name main
. After the function name and args (we do not have any in this case), we specify the return
type. The return type here is !void
. The !
specifies that the function might return error
. We can expand the !void
something like <error-type> or <void>
.
Next, we take the writer
function from the imported std
library.
Note: It is too long!!! But it clearly says what the programmer is trying to do and what the compiler will do.
Finally, we use print
from the method from the stdout
to print the actual strings out. The print statement is similar to how we will do in other low-level languages like C / Rust.
Note:
.{}
. in the second argument to theanonymous
struct literal.
That is it. We can run this zig code using zig run hello.zig
.
As you can see, the function is simple and easier to understand. The language neither has macros nor magically print the result.
No magic here!
No Null pointers
Oh yeah! Everyone agrees Null Pointer is a billion-dollar mistake.
Zig does not have null
, but they provide optional
. Optional type provides safety and better readability.
const optional_world_answer: ?i32 = 42;
The ?
specifies the type is optional
. It can either accept null
or any i32
integer. null
is an allowed type in ziglang.
We can safely access the optional
using the if-let
syntax.
if (optional_world_answer) |world_answer| {
// here `world_answer` is i32 and not null.
}
Optional makes your language verbose, the benefits of them in safety, readability stands out.
Error handling
Zig is inclusive of errors too. It handles errors as values. The zig compiler ensures errors are handled and complains when they are not.
For example,
fn get_i64() !i64 {
return error.notImplemented;
}
pub fn main() void {
// we are basically discarding the result
_ = get_i64();
}
The above code will throw a compiler error that we are not handling error and the error gets discarded. Always remember errors are values. We can fix it by using catch
or try
.
// error handling with `catch`
let number = get_i64() catch |err| {
// do something with error
};
// error handling with `try`
let number = try get_i64();
// well when you are sure that it won't error
let number = try get_i64() catch unreachable
Zig provides refreshing error handling.
Comptime
Zig provides a comptime
keyword to specify that a particular value and type are available during the compile-time. You can use comptime
in three different places.
- parameters
- variables
- expressions
comptime in parameters
Zig uses the comptime in parameters to duck type and implements generics.
fn generic_fn(comptime T: type, a: T, b: T) {...}
We can call generic_fn
like the following:
generic_fn(i32, 10, 11);
The function call-site expects type as a comptime parameter.
comptime in variables
Comptime in variables is another good feature in zig. It guarantees that the compiler will perform all the load and store operations during the compile time itself.
comptime in expressions
Similarly, we can mark an expression as comptime
such that it will evaluate at the compile time.
Other features that stand out are:
- Easier integration with C and other C-like languages.
- Std library code is readable.
- Simple grammar for the language.
The things that need to improve in zig are:
- Although error handling is refreshing, there is no way to pass a context with errors.
- Extreme importance on readability leads you to write low-level code.
- The language is in its very early days, and it will be interesting to see how it evolves (with more features).
Overall, Zig has an excellent future. It will be a replacement for C, and I hope it will succeed.