zig
zig copied to clipboard
Proposal: `packed struct(Backing)` -> `packed(Backing) struct`, support `packed(Backing) union`
Background
In status-quo, packed struct
and packed union
types are guaranteed to occupy the minimum number of bits required.
For packed struct
this is the sum of the number of bits of their fields,
for packed union
(which status-quo requires to be untagged), it's the maximum number of bits of its states.
Status-quo allows the syntax packed struct(Backing)
to specify the backing integer type,
which is a convenient way to have the compiler assert the number of bits occupied.
(side note: currently undocumented in the corresponding langref section.)
I think the same mechanism would be useful to have for packed union
types.
I assume the reason this is currently not supported by the language is that
union(X)
is used to specify X as the tag type,
and overloading it to instead specify X as the backing type in packed union(X)
would be confusing.
Proposal
I propose the backing type to instead become the syntactic "argument" of the packed
keyword.
With this, status-quo packed struct(Backing)
becomes packed(Backing) struct
,
and packed(Backing) union
becomes unambiguously expressible.
I then secondly propose supporting packed(Backing) union
in the language.
std.builtin.Type.Union
would have to gain field backing_integer: ?type
from std.builtin.Type.Struct
in order for @typeInfo
and @Type
to integrate with this additional information.
Potential drawbacks
This slightly reduces grep-ability for packed struct
syntax - I'm not sure how often this comes up in workflows.
If that is a concern, a mitigation against this would be to order packed
after the container type,
yielding f.e. struct packed
, struct packed(u16)
, union packed(u12)
.
Small bikeshed: I think it would make sense to make ContainerLayout
be a tagged union, wherein the @"packed"
member is of type type
, as for any state where the layout isn't packed, it's illegal to specify the backing_integer
type - unless specifying null for .@"packed"
is made to mean "infer the backing type", as is what happens for field alignment = 0.
@InKryption Sure, that's a larger change than necessary for the proposal, but it does better reflect the logic of status-quo.
Note that this would require reverting should the language ever allow an explicitly-sized extern
type, f.e. packed(u16) extern struct
, in the future.
I dont read packed struct(T)
as T modifying the struct keyword. packed struct
is a single entity kind that doesnt need parentheses to be instantiated. inline fn
is another example.
if this were to change I'd prefer struct packed(T)
but I feel that needlessly hurts readability.
What if
packed struct
was|_| struct
- What if
packed(backingInt) struct
was|backingInt| struct
If this syntax is already used to capture values, maybe it can go in the other direction of wrangling them too.
That won't work. It makes the syntax require lookaheads and looks terribly inconsistent overall.
bits {...}
bits
sounds incredibly vague, and doesn't solve the problem in the original issue.