DEV Community

Alex Spinov
Alex Spinov

Posted on

Zig Has a Free Systems Language — Here's Why C Programmers Are Switching

C is 50 years old. Rust has a steep learning curve. Zig is the middle ground — simple, fast, and safe enough.

What is Zig?

Zig is a general-purpose systems programming language designed to be a better C. No hidden control flow, no hidden allocations, no undefined behavior by default.

Quick Start

# Install
brew install zig

# Create a project
mkdir my-app && cd my-app
zig init
zig build run
Enter fullscreen mode Exit fullscreen mode

Hello World

const std = @import("std");

pub fn main() void {
    std.debug.print("Hello, {s}!\n", .{"World"});
}
Enter fullscreen mode Exit fullscreen mode

Variables and Types

const std = @import("std");

pub fn main() void {
    // Immutable
    const x: i32 = 42;
    const name: []const u8 = "Alice";

    // Mutable
    var count: u32 = 0;
    count += 1;

    // Type inference
    const pi = 3.14159;

    // Arrays
    const nums = [_]i32{ 1, 2, 3, 4, 5 };

    // Slices
    const slice = nums[1..4]; // [2, 3, 4]

    std.debug.print("count = {}\n", .{count});
}
Enter fullscreen mode Exit fullscreen mode

Error Handling (No Exceptions)

const FileError = error{
    NotFound,
    PermissionDenied,
    IoError,
};

fn readFile(path: []const u8) FileError![]u8 {
    const file = std.fs.cwd().openFile(path, .{}) catch |err| {
        return switch (err) {
            error.FileNotFound => FileError.NotFound,
            error.AccessDenied => FileError.PermissionDenied,
            else => FileError.IoError,
        };
    };
    defer file.close();
    return file.readToEndAlloc(allocator, 1024 * 1024);
}

pub fn main() void {
    const content = readFile("config.txt") catch |err| {
        std.debug.print("Error: {}\n", .{err});
        return;
    };
    std.debug.print("Content: {s}\n", .{content});
}
Enter fullscreen mode Exit fullscreen mode

Comptime (Compile-Time Execution)

// Zig's killer feature: run code at compile time
fn fibonacci(n: u64) u64 {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
}

const fib_10 = comptime fibonacci(10); // Computed at compile time!

// Generic function via comptime
fn max(comptime T: type, a: T, b: T) T {
    return if (a > b) a else b;
}

const result = max(i32, 10, 20); // 20
const fresult = max(f64, 3.14, 2.72); // 3.14
Enter fullscreen mode Exit fullscreen mode

C Interop (Drop-in Replacement)

const c = @cImport({
    @cInclude("stdio.h");
    @cInclude("stdlib.h");
});

pub fn main() void {
    _ = c.printf("Hello from C!\n");
    const ptr = c.malloc(100) orelse unreachable;
    defer c.free(ptr);
}
Enter fullscreen mode Exit fullscreen mode

Zig can import any C header file and call C functions directly. No bindings needed.

Zig vs C vs Rust

Feature Zig C Rust
Memory Safety Optional (debug) None Borrow checker
C Interop Native N/A FFI
Build System Built-in Make/CMake Cargo
Compile Time Comptime Macros Proc macros
Learning Curve Medium Low High
Undefined Behavior Detectable Silent Prevented

Who Uses Zig?

  • Bun (JavaScript runtime) — written in Zig
  • TigerBeetle (financial database) — written in Zig
  • Mach Engine (game engine) — written in Zig

Need high-performance data extraction? Check out my web scraping actors on Apify Store — optimized for speed. For custom solutions, email spinov001@gmail.com.

Top comments (0)