Mutating a global array at comptime in Zig

99 views Asked by At

I am trying to build a "static" data array and keep struggling with comptime/runtime failure. This is a condensed version of what I am trying:

const std = @import("std");

var global_array: [4]u8 = undefined;

fn fill(comptime arr: []u8) void {
    for (arr) |*c| {
        c.* = 'Z';
    }
}

test "Comptime mutation" {
    comptime {
        fill(&global_array);
    }
    try std.testing.expect(global_array[0] == 'Z');
}

Which yield the error message:

error: unable to evaluate comptime expression
        c.* = 'Z';
        ~~~~^~~~~
note: operation is runtime due to this operand
        c.* = 'Z';
        ~^~
note: called from here
        fill(&t);

I have found this answer which seems to use the same pattern in the load_error_codes_with_context function and was not able to spot the difference -> https://stackoverflow.com/a/77357351/9756362

My questions are then:

  • Is there a way to make the above test succeed ?
  • If not, is there another way to achieve this type of 'comptime mutation' to build complex data structure at compile time ?
1

There are 1 answers

0
NyuB On

As pointed by sigod, wrapping the comptime var access in a dedicated struct like in this SO answer solves the problem :

const global_array = blk: {
    comptime var array: [4]u8 = undefined;
    const result = struct {
        fn get() []u8 {
            return &array;
        }
    };
    break :blk result;
};

fn fill(comptime arr: []u8) void {
    for (arr) |*c| {
        c.* = 'Z';
    }
}

test "Comptime mutation" {
    comptime {
        fill(global_array.get());
    }
    try expect(global_array.get()[0] == 'Z');
}