#Pass allocator at compile time

1 messages · Page 1 of 1 (latest)

green fable
#

Is there a way to pass an allocator at compile time?

I am learning Zig by building a small Matrix library. For the initial version I
thought it would be good enough if every operation (e.g. adding two matrices
together) would allocate a Matrix for the result.

I don't want to pass an allocator to every matrix operation. Instead I would
like to pass an allocator at compile time.

So that a.add(allocator, b) becomes a.add(b). Is this possible?

I've tried:

const std = @import("std");
const Allocator = std.mem.Allocator;
const expect = std.testing.expect;

fn Matrix(comptime T: type, comptime allocator: Allocator) type {
    return struct {
        const Self = @This();

        elements: []T = undefined,
        allocator: Allocator = allocator,

        rows: usize,
        columns: usize,

        pub fn init(rows: usize, columns: usize) !Self {
            return Self{
                .elements = try allocator.alloc(T, rows * columns),
                .allocator = allocator,
                .rows = rows,
                .columns = columns,
            };
        }
    };
}

pub const Mat = Matrix(
    f32,
    std.heap.ArenaAllocator.init(std.heap.page_allocator),
);

test "Initalize matrix" {
    var m = Mat.init(16, 16);
    _ = m;
}

This throws the following error:

tmp.zig:28:33: error: expected type 'mem.Allocator', found 'heap.arena_allocator.ArenaAllocator'
/nix/store/wrm7r7msb7yrhnwaxgbpn2mc7kla6x4a-zig-0.11.0/lib/zig/std/heap/arena_allocator.zig:8:28: note: struct declared here
/nix/store/wrm7r7msb7yrhnwaxgbpn2mc7kla6x4a-zig-0.11.0/lib/zig/std/mem/Allocator.zig:1:1: note: struct declared here
tmp.zig:5:49: note: parameter type declared here
dim glacier
#

No, but you could take the allocator as a parameter in your init function instead

#

But - do you need to the width/height of the matrices to be known at runtime? If they are known at compile time then you don't need an allocator at all for this

green fable
#

I am not sure yet TBH, in the end I would like to implement a basic neural net, whos model can be hotswaped at runtime. But maybe I just spend to much time in Python and laying out everything statically is the way to go.

green fable
#

@dim glacier So I've tried to get rid of allocations for now, but I can't get the set function to work

const std = @import("std");
const expect = std.testing.expect;
const assert = std.debug.assert;

fn Matrix(comptime T: type, comptime rows: usize, comptime columns: usize) type {
    return struct {
        const Self = @This();

        elements: [rows * columns]T = undefined,

        pub fn set(self: Self, r: usize, c: usize, v: T) void {
            self.elements[r * columns + c] = v;
        }

        pub fn get(self: Self, r: usize, c: usize) T {
            return self.elements[r * columns + c];
        }
    };
}

pub const F32_4x4 = Matrix(f32, 4, 4);

test "Set and get value" {
    const m: F32_4x4 = F32_4x4{};
    m.set(0, 0, 1);
    try expect(m.get(0, 0) == 1);
}

The error is:

static_matrix.zig:12:26: error: cannot assign to constant

Do I need to do this differently? Struct fields are not const by default right?

gaunt quest
#

I think the issue here is your member function signature. You have pub fn set(self: Self, ...) which means that you're passing by value (or possibly by a const pointer under Zig's rules, but the difference is unimportant here).

In order to mutate self, you'll want to take a pointer to it like this pub fn set(self: *Self, ...) and ensure that any instance of your Matrix type that's being mutated is a var. That would mean also changing the first line of your test to be var m: ....

iron perch
# green fable Is there a way to pass an allocator at compile time? I am learning Zig by build...

So the other ideas suggested are probably the way to go, but you actually can do what you originally asked about.

const std = @import("std");

fn Matrix(comptime T: type, comptime allocator: std.mem.Allocator) type {
    return struct {
        elements: []T = undefined,
        rows: usize,
        columns: usize,

        pub fn init(rows: usize, columns: usize) !@This(){
            return .{
                .elements = try allocator.alloc(T, rows * columns),
                .rows = rows,
                .columns = columns,
            };
        }
    };
}

var global_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
pub const Mat = Matrix(
    f32,
    global_arena.allocator(),
);

test "Initalize matrix" {
    var m = try Mat.init(16, 16);
    _ = m;
}
green swan
#

? allocator here cant be comptime

iron perch
green fable
#

@gaunt quest thank you 🙏 , this makes sense now

gaunt quest
#

Glad to hear it!