*ฅ^•ﻌ•^ฅ* ✨✨  HWisnu's blog  ✨✨ о ฅ^•ﻌ•^ฅ

Reduce  Zig's verbosity

Introduction

My biggest gripe when I started learning Zig was its syntax: one of the most verbose programming language I've ever seen, even more verbose than Rust!

Example of Zig Code

Below is an example of Zig code that generates random numbers:

const std = @import("std");


fn gen_randNum(minVal: u32, maxVal: u32, arraySize: u32) ![]u32 {
    const seed = std.time.milliTimestamp();
    var rnd = std.rand.DefaultPrng.init(@intCast(seed));
    const randNums = try std.heap.page_allocator.alloc(u32, arraySize);

    for (randNums) |*num| {
        num.* = rnd.random().intRangeAtMost(u32, minVal, maxVal);
    }
    return randNums;
}

pub fn main() void {

    const minVal: u32 = 1;
    const maxVal: u32 = 1_000;
    const arraySize: u32 =1_000;

    var randomNumbers: []u32 = undefined;
    if (gen_randNum(minVal, maxVal, arraySize)) |numbers| {
        randomNumbers = numbers[0..];
    } else |err| {
        std.debug.print("Error generating random numbers: {}", .{err});
        return;
    }
    
    std.debug.print("Unordered array:\n", .{});
    for (randomNumbers[randomNumbers.len - 50 ..]) |item| {
        std.debug.print("{} ", .{item});
    }
}

Verbose Syntax

Take a look at the consts, vars and print statements. No matter how you spin it, in my opinion it's too long and verbose.

This is the one aspect of Zig that I dislike.

Compacted Version

Fortunately, there's a way to reduce this verbosity. Below is the compacted version of the same Zig code:

const std        = @import("std");
const print      = std.debug.print;
const tMilli     = std.time.milliTimestamp;
const RandGen    = std.rand.DefaultPrng;
const PageAlloc  = std.heap.page_allocator;


fn gen_randNum(minVal: u32, maxVal: u32, arraySize: u32) ![]u32 {
    const seed = tMilli();
    var rnd = RandGen.init(@intCast(seed));
    const randNums = try PageAlloc.alloc(u32, arraySize);

    for (randNums) |*num| {
        num.* = rnd.random().intRangeAtMost(u32, minVal, maxVal);
    }
    return randNums;
}

pub fn main() void {

    const minVal: u32 = 1;
    const maxVal: u32 = 1_000;
    const arraySize: u32 =1_000;

    var randomNumbers: []u32 = undefined;
    if (gen_randNum(minVal, maxVal, arraySize)) |numbers| {
        randomNumbers = numbers[0..];
    } else |err| {
        print("Error generating random numbers: {}", .{err});
        return;
    }
    
    print("Unordered array:\n", .{});
    for (randomNumbers[randomNumbers.len - 50 ..]) |item| {
        print("{} ", .{item});
    }
}

Benefits of Compacted Syntax

Notice how much cleaner the code is! Variable assigments are now much more compact.

What I did was to put the method/function chainings into consts, especially the longer ones. Although this approach adds the number of lines vertically , it reduces the horizontal width when reading the code.

In my opinion, reading vertically is much easier compared to reading long lines of code horizontally. I acknowledge this might not be considered best practice to write Zig, but for me, compacting the syntax makes Zig much less verbose and more enjoyable to write.

Conclusion

I'm curious to know your thoughts..but for me the "fun-factor" is quite important. If I'm enjoying the process of writing in a programming language, that means I'm also having fun! This is why I find myself unable to stop writing in Zig – it's as simple as C and brings me joy!


Note: the provided code is a simple example, but imagine working on a larger codebase, where the compact version can provide significantly more readable code.

#low level #programming #syntax #verbose #zig