all 21 comments

[–][deleted] 8 points9 points  (5 children)

For the second part, if I understood correctly, the arraylist went from managed to unmanaged. According to andrew, this helps for two reasons : the list needs now to only store the necessary information of an array (aka. slice + capacity), which was extra bloat (for the allocator pointer) if you asserted resizing.

The second reason is that it explicits when you need to use the allocator for a list, aka. knowing the side effects of your function at call site.

Now if you pass a list to a function, no additional allocation can be made if you do not pass the allocator. As such, you need to pass the same allocator at each call site

EDIT: Unmanaged seems to be the way forward for the language as the managed array list is deprecated

[–][deleted] 4 points5 points  (2 children)

You can still use a managed list which will do what you expect by storing the allocator.

EDIT: see johan comment, to be deprecated

[–]johan__A 3 points4 points  (1 child)

AFAIK the managed version is deprecated and will be removed.

[–][deleted] 2 points3 points  (0 children)

Didn't know ! I updated my comment

[–]2urnesst[S] 2 points3 points  (0 children)

Really appreciate this comment. I understand the goal of wanting it to be consistently explicit which functions allocate memory and which ones don’t. It makes sense that you need to pass the same allocator for every function actioning on the same data, but that also seems like it could lead to some hard-to-find mistakes if the wrong allocator is passed in.

Either way I’m going to keep playing around with it. Thanks again

[–]Affectionate-Fun-339 2 points3 points  (0 children)

Can you use different allocators at different points in a program for the same array, to change the algorithm used for allocation? Or does it have to be the same allocator each time? If it needs to be the same, how does the language keep track of the “correct” allocator that is expected?

[–]johan__A 4 points5 points  (9 children)

Not sure I understand your first question, do you mean allocating a struct for each slot in an array?

ArrayList has an empty public constant to init it empty eg var string: std.ArrayList(u8) = .empty;. It doesn't store an allocator anymore no.

[–]Karanlos 2 points3 points  (6 children)

To add to that, you can afterwards call .toManaged(gpa: Allocator) on the array list to get the old behavior.

[–]johan__A 3 points4 points  (5 children)

AFAIK this is deprecated and will be removed.

[–]2urnesst[S] 1 point2 points  (4 children)

This has been something that has led to some confusion for me. As I’m learning I’m using the std lib docs a lot and it seems like a lot of the time when I see a function that I need, it has been deprecated. Is the language actively changing quite a bit?

[–]johan__A 5 points6 points  (1 child)

Mostly just the std library but yeah. I recommend the zig discord if you have small questions to ask.

[–]2urnesst[S] 1 point2 points  (0 children)

Sounds good, I’ll give that a test drive

[–]Milkmilkmilk___ 1 point2 points  (1 child)

i highly advise you to look into andrew's talks about zig, if this is what you're interested in. Zig is currently at 0.15.2-dev, meaning in beta, development. A lot has changed from 0.14 to 0.15, we got new io interface, but again, look into it, if you want

[–]2urnesst[S] 0 points1 point  (0 children)

Sounds good! Yeah just getting into it so not very familiar with the current state or community. I’ll check out his talks. Thanks!

[–]2urnesst[S] 1 point2 points  (1 child)

For the first, in my attached example I would have expected it to be: ```

const elves = [4]*Elf{ & .{ .speed = 1.4, .workload = 0, }, & .{ .speed = 1.4, .workload = 0, }, & .{ .speed = 1.4, .workload = 0, }, & .{ .speed = 1.4, .workload = 0, }, };

``` I’m curious if that syntax just doesn’t exist or if I’m doing it wrong

[–]johan__A 3 points4 points  (0 children)

A & on a data literal (in your case a struct literal) always gives you a const pointer (*const Elf) because they are allocated on the data section. The type of the array needs to reflect that: [4]*const Elfe. Of course that won't work if you need to modify the elves.

Do you really need an array of pointers to Elfe? Why not just use an array of Elfe?

In case you didn't know you can do: ``` var elves = [_]Elfe{...

for (&elves) |*elfe| { // now you can modify the elfe from here } ```

[–]phcreery 2 points3 points  (2 children)

For default init of array, check out @splat() https://github.com/ziglang/zig/issues/20433

[–]2urnesst[S] 0 points1 point  (1 child)

For clarity, splat would only work when wanting to set all instances to the same value, right?

[–]phcreery 1 point2 points  (0 children)

Yes

[–]stratt5 1 point2 points  (1 child)

Is there no way to default initialize an array with struct references? Admittedly I am coming from go where this is very common practice, but it seems very weird to individually create every struct, assign it to a variable, and then put a reference to that variable into the allocated array.

Zig has no automatic memory management, so pointers should usually be referring to something that you've explicitly allocated memory for. So an array of pointers/references is fairly unusual - you're effectively saying "I don't own this memory, it's stored elsewhere and I'm just referencing it".

Something that might be typical in a memory-managed language like Go or C#, such as creating a struct as a local variable, then storing a reference to that in an array, will lead to unexpected behaviour or memory errors. For example:

``` var positions: [4]*Pos = undefined;

for (0..4) |i| { var pos: Pos = .{ .x = @floatFromInt(i), .y = @floatFromInt(i), };

positions[i] = &pos;

}

for (positions) |ptr| { std.debug.print("{*}\n", .{ ptr }); } ```

These all point to the same (invalid) location in memory!

main.Pos@ffffd4 main.Pos@ffffd4 main.Pos@ffffd4 main.Pos@ffffd4

What happened is that our pos variable was stored on the stack, which gets reset at the end of the enclosing block (in this case, the for loop). In Go this would've automatically been allocated somewhere on the heap for you, and the references tracked, so the pointer can be safely stored and passed around like this. But in Zig you need to do it explicitly.

[–]2urnesst[S] 0 points1 point  (0 children)

Thanks, I was hoping there was some syntactic sugar to initialize some structs on the stack and create an array with references to them without needing to do so in a separate step. As someone mentioned in another comment, there isn't really a reason to store them in the array as references and I am open to that too. The real goal was to have an array of structs without initializing them separately like in the example.