#19674 is rejected but #5038 is accepted

I used to think that #19674 was a prerequisite for #5038. When #5038 was accepted, I thought #19674 would be accepted soon, but to my surprise, it was recently rejected.

Does this mean the appearance of other alternatives?

Can you provide a little more context about what you’re talking about? I tend to skip posts that don’t make any sense without following a link.

It’s about the following syntaxes

const a: T = .{};  // now mandatory
const a = T{};  // now forbidden

const x = [_]u8{ 1, 2, 3 }; // still allowed
const x: [_]u8 = .{ 1, 2, 3 }; // considered but rejected
2 Likes

I’m wondering if it’s indicative that they might remove the underscore [_] syntax entirely, meaning that neither form will be allowed.

const x = [_]u8{ 1, 2, 3 };    // not allowed
const x: [_]u8 = .{ 1, 2, 3 }; // not allowed
const x = [3]u8{ 1, 2, 3 };    // not allowed
const x: [3]u8 = .{ 1, 2, 3 }; // ok

[_] is almost too convenient and leaves room for lazy programmers to make mistakes; maybe your code indirectly depends on there being three entries, but then one day someone adds a fourth and now your assumptions no longer hold. [3] makes everything more explicit and less surprising because now it’s a compile error if you have too many or too few elements.

I rarely find myself needing to use [_]. If I need a sequence of constant data of a variable or unknown length, a slice &.{} is often the better choice and composes better when nested under multiple levels.

2 Likes

anything to back this claim? any real-life examples?

a: [_]u8 = .{ 1 , 2, 3 }; is kinda redundant when you can just a = .{ 1, 2, 3 };

It does have the nice property of providing a result u8 type to the elements, but you can achieve that with a slice too; and the compiler preserves comptime known slice lengths where possible, so you dont loose that either.

1 Like

Fair point.

I used to prefer comptime arrays over comptime slices, simply because when I was first learning Zig, using comptime slices always gave me the illusion of returning a stack pointer. After stepping out of my comfort zone, I found that comptime slices can indeed replace the majority of scenarios where inferred-length arrays are used.

Especially note that #35389 allows directly coercing a comptime slice into an array pointer, which is probably the main recent change affecting the disappearance of [_]T.

The motivation for using [_]T is to avoid hardcoding.

Sometimes the list length of ‘3’ is predetermined, so we should avoid changing it by accident, and clearly use [3]T. More often, though, the list length is determined by the contents of the list, and in that case, ‘3’ is a hard-coded value that should be avoided in the source code.

But I agree, currently comptime []T can cover this use case, I had overlooked this before.

3 Likes

[_] syntax is cute, but ultimately it could be a ZLS or even zig fmt feature because it can be inferred by counting the expressions.

I think the main value is about conveying/clarifying intent. Value type vs reference type semantics aside, the main distinction between an array and a slice is that the array’s length is a property of the type, while the slice’s isn’t.

const a: [3]u8 = .{ 1, 2, 3 };
const b: *const [3]u8 = &.{ 1, 2, 3 };
const c: []const u8 = &.{ 1, 2, 3 };

a and b both signal to the reader that the fact that the array length is 3 is significant. For c on the other hand the length probably isn’t as significant, and adding or removing elements is less likely to break assumptions within the program.

To use a reduced real world example from some math code I’ve written, I have two arrays like these:

const sin_coefficients = [_]f64{
    0x0p+0,
    0x1.87de2ap-2,
    0x1.6a09e68p-1,
    0x1.d906bdp-1,
    0x1p+0,
};
const cos_coefficients = [_]f64{
    0x0p+0,
    0x1.921d2p-7,
    0x1.92156p-6,
    0x1.2d8658p-5,
};

Math specifics aside, do you see why a reader might begin to ask questions when reviewing this code? One array has a length of 5, and the other has a length of 4. Was this a mistake on the author’s part? Is there a superfluous element or an element that is missing? Using explicit [5]f64 and [4]f64 would more clearly communicate that this discrepancy is intentional and not a mistake. (In this case the underlying reason for the different lengths has to do with sine and cosine being even and odd functions, respectively.)