ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
35.17k stars 2.57k forks source link

Proposal: add `.len` field to vector values #17886

Open mlugg opened 1 year ago

mlugg commented 1 year ago

I'm fairly sure status quo was just an oversight.

If x is a tuple or array, x.len is a comptime-known usize whose value is the length of the aggregate. It would make perfect sense for this to also apply to vector values, i.e. when x has a vector type. With the current implementation, this would also automatically make for loops over vectors work; currently they don't, and you get a slightly odd error precisely because the corresponding Sema logic assumes that vectors have a .len field.

Put simply, the following test should pass:

test "vector has len field" {
    const v: @Vector(4, usize) = .{ 10, 11, 12, 13 };
    try std.testing.expectEqual(@as(usize, 4), v.len);
    for (v, 10..) |x, i| {
        try testing.expectEqual(i, x);
    }
}
expikr commented 1 year ago

And slice syntax

nektro commented 1 year ago

i'm impartial to this change on its face, but you should likely still have to coerce to array to loop over it since vecs are packed when the element type is bool/u1.

mlugg commented 1 year ago

@nektro Why would vectors being bit-packed impact your ability to loop over them? A for loop is essentially desugarable to a ranged loop which indexes into each operand. You can index into a vector at runtime - i.e. the snippet below works - so why not loop directly?

for (0..vec.len) |i| { // depends on the actual .len field of this proposal
    const x = vec[i];
    _ = x;
}
andrewrk commented 1 year ago

No good because the vector can have pointer elements to structs in which case field access is supposed to be lowered to a gather (or scatter for setting the value)

mlugg commented 1 year ago

Hm - that functionality very much doesn't exist today, and I can't find a proposal suggesting it. Do you have a reference to one?

Just to check, is the idea there that if struct_vec has type @Vector(n, *struct { x: u32 }), then &struct_vec.x has type @Vector(n, *u32) or something like that? Would gather not work through nested field accesses (since the intermediary struct values can't be stored in vectors)? Overall, to me, this seems like a somewhat odd piece of functionality to assign to general field access syntax - why not instead provide a builtin? It's also quite strange that x.@"0" would have a valid meaning distinct from x[0].

cryptocode commented 1 year ago

Vectors and loops: https://github.com/ziglang/zig/issues/5761

expikr commented 1 year ago

.len would also greatly help with the generic here: https://github.com/ziglang/zig/issues/17875

Without .len the inline function cannot receive vector types, and coercing into arrays before passing it would mean that you'd need to hand-write the array length at every call site.

Pyrolistical commented 1 year ago

@mlugg if this gets rejected, should this other thing you found be reported as a bug?

for loops over vectors [...] currently they don't, and you get a slightly odd error precisely because the corresponding Sema logic assumes that vectors have a .len field

Trevor-Strong commented 8 months ago

What about changing vector field access vec[..].field? This lets vec.len exist and makes it more clear that you are accessing the vector elements instead of the the vector itself. It would also make vectors of struct pointers consistent with array pointers since vec[0] for @Vector(n, *[len]T) gets the first vector element instead of the first element each array element.