It looks like @mlugg has done in incredible job at implementing a destructuring syntax into the compiler
Pull Request:
Proposal:
To quote his commit:
This change implements the following syntax into the compiler:
const x: u32, var y, foo.bar = .{ 1, 2, 3 };
A destructure expression may only appear within a block (i.e. not at
comtainer scope). The LHS consists of a sequence of comma-separated var
decls and/or lvalue expressions. The RHS is a normal expression.
A new result location type, destructure, is used, which contains
result pointers for each component of the destructure. This means that
when the RHS is a more complicated expression, peer type resolution is
not used: each result value is individually destructured and written to
the result pointers. RLS is always used for destructure expressions,
meaning every const on the LHS of such an expression creates a true
stack allocation.
Aside from anonymous array literals, Sema is capable of destructuring
the following types:
Tuples
Arrays
Vectors
A destructure may be prefixed with the comptime keyword, in which case
the entire destructure is evaluated at comptime: this means all vars
in the LHS are comptime vars, every lvalue expression is evaluated at
comptime, and the RHS is evaluated at comptime. If every LHS is a const, this is not allowed: as with single declarations, the user
should instead mark the RHS as comptime.
There are a few subtleties in the grammar changes here. For one thing,
if every LHS is an lvalue expression (rather than a var decl), a
destructure is considered an expression. This makes, for instance, if (cond) x, y = .{ 1, 2 }; valid Zig code. A destructure is allowed
in almost every context where a standard assignment expression is
permitted. The exception is switch prongs, which cannot be
destructures as the comma is ambiguous with the end of the prong.
A follow-up commit will begin utilizing this syntax in the Zig compiler.
Personally I could never understand what the point of this would be for struct initializers as you can have default initializers on any field and then just do var foo: Foo = .{};, or if you want multiple “constructors” you could just have a dedicated function in Foo’s namespace and call it instead like var foo = Foo.initSome();.
Hmm I don’t think I understand your argument. The code snippets I brought up will work with const too so const foo: Foo = .{}; and const foo = Foo.initSome() are all OK. The only time where this would fall apart is if it was not possible to evaluate initSome() at compile-time.
No actually, scratch my last remark. const foo = Foo.initSome() should still work in local scope even if initSome() would not be comptime. The only time it wouldn’t work is if we were trying to evaluate it in comptime-scope such as as a global-scoped const, etc.
where there is a lot of extra ceremony when all you really want to do is peel apart multiple associated values.
I do agree, I can’t seem to come up with a case where “var” is getting in the way.
I’ve got a bunch of these kinds of coupled assigns in lots of Vulkan code. I’ll go through them at some point and see if I can cough up some of the edge cases.
Mhm, I see. I do agree with the usage of destructuring in your example of by-passing the need for tuples, but I still don’t see any point in allowing destructuring into struct fields as mentioned in the original post I was replying to