#Beginner: Is there a way to make this more "Zig-like" ?

1 messages · Page 1 of 1 (latest)

mighty cargo
#

Hi,

I'm new to zig and I was making a function that duplicates 2D arrays. But I found myself writing code that would be quite the same as if I was writing in C. I've spent a long time in C, so I'd like an exterior point of view that could tell me if I could achieve the same result in a way that would be more "Zig-like".

fn dupeMatrix(allocator: mem.Allocator, matrix: []const []const u8) mem.Allocator.Error![][]u8 {
    var arr = try allocator.alloc([]u8, matrix.len);
    var i: usize = 0;

    while (i < matrix.len) : (i += 1)
        arr[i] = allocator.dupe(u8, matrix[i]) catch |err| {
            while (i > 0) : (i -= 1)
                allocator.free(arr[i - 1]);
            allocator.free(arr);
            return (err);
        };

    return arr;
}

Thanks for reading this !

subtle coral
#

something like this:

var arr: std.ArrayList([]u8) = try .initCapacity(allocator, matrix.len);
errdefer for(arr.items) |item| allocator.free(item);
for (matrix) |matrix_item| {
    arr.appendAssumeCapacity(try allocator.dupe(u8, matrix_item));
}
return arr.toOwnedSlice(allocator);
  • for instead of while
  • errdefer for error handling
  • arraylist to make the error handling easier
mighty cargo
#

Oh wow you're from the Bun Team, you guys are always top notch whenever I ask questions on the Bun Server and now on here.

mighty cargo
#

Does ArrayList have a low overhead ?

subtle coral
#

yeah. arr.items only has the ones that were added. using a regular slice you would need to keep track of how far to deinit because some would have never been initialized

#

this usage of arraylist is nearly identical to using a slice directly - initCapacity allocates a slice. the arraylist itself has two fields items and capacity. and appendAssumeCapacity does items.len += 1; items[items.len - 1] = value; (with debug assertions for safety)

#

when using an arraylist with regular .append(), it can be slower because when it hits the capacity it needs to reallocate the slice

mighty cargo
#

If we already pre-initliased the ArrayList with the correct size. The advantage of appendAssumeCapacity over append is just that it doesn't potentially return an error so we don't need try ?

Because it still looks like is asserts the capacity:

pub fn addOneAssumeCapacity(self: *Self) *T {
    assert(self.items.len < self.capacity);

    self.items.len += 1;
    return &self.items[self.items.len - 1];
}
#

Pretty cool

#

Thanks for the help

sinful dagger
mighty cargo
#

Mmh interesting, but I would be on the team "no side effects in asserts"

past osprey
#

the assert itself has no side effects, they are saying that if the value you are asserting is gotten with side effects it wont be removed in non safe modes ie assert(1 ==1) will be removed but assert(fnWithSideEffects() == 1) wont be.
This is because std.debug.assert is just a normal function, whereas in C its a macro which doesnt generate code if asserts are disabled.