Conversion from `[]T` to `[N]T` -- just undocumented or not intended?

I noticed that this sort of coercion from a slice to an array pointer works:

fn f() void {
    var slice: []const usize = &.{1, 2, 3};
    _ = g(slice[0..2]); // coercion from slice (of proper size) to array pointer
}

fn g(buf: *const [2]usize) usize {
    return buf[0] + buf[1];
}

But I don’t see this listed as a supported coercion. Anyone know if it is meant to work but is just undocumented? Or is it not intended to work and I shouldn’t rely on it?

See the comment in the code of the slices section of the docs.

    // If you slice with comptime-known start and end positions, the result is
    // a pointer to an array, rather than a slice.
    const array_ptr = array[0..array.len];
    try expect(@TypeOf(array_ptr) == *[array.len]i32);
8 Likes

I would never ever dare to write code trusting that coercion (apart from it being unreadable).

You’ve probably already done so: std.mem.readInt

The title is misleading, there is no coertion from slice to array. There is from pointer to array to slice, but that’s trivial: a pointer to an array of length N is easily convertible to a slice of length N.

In this case slicing with comptime known bounds results in a pointer to an array because it provides more information than generating a slice. It’s peculiar, and a welcome addition when it was added to Zig, but again nothing particularly mindblowing, especially given my first point, that pointers to array coerce so slices (so you get more info if you want, otherwise the value will coerce to a slice without you having to do anything).

8 Likes

So actually, there’s no coercion here, there would instead be one if it were e.g. something like this:

// no change here
fn f() void {
    var slice: []const usize = &.{1, 2, 3};
    _ = g(slice[0..2]); // now a coercion from an array pointer to slice
}

// now takes a slice
fn g(buf: []const usize) usize {
    // ...
}

Also, if the call in the original code was something like g(slice[0..3]) or g(slice[0..some_runtime_value]), it would not compile.

Best of all, I see no drawbacks to Zig setting the types this way. I have to say this is actually genius!

1 Like

Thank you. I’d forgotten about that even though I’d read it years ago.

It’s extremely useful. The alternative would be to copy to an array, which is much less convenient.

That’s exactly how I’m using it and then due to my memory lapse I was surprised that it worked.

1 Like