Differences in location of type on struct assignments?

Hi! Newb here, so bear with me if this is a dumb question…

Consider the two following ways of initializing a struct:

var foo: some_type = .{};
var bar = some_type{};

What is the difference between foo and bar? Is there one?

Since types are comptime values, I’d expect there’s no difference between them. I seem to see the latter one more in code samples, though, e.g.:

var gpa = std.heap.GeneralPurposeAllocator(.{}){};

instead of

var gpa: std.heap.GeneralPurposeAllocator(.{}) = .{};

In the official documentation.

Both seem to compile just fine and (IMO, of course) the second one makes the generic nature of the type more clear. I’m wondering if there is a reason for it that’s to do with something deeper in the language somewhere.

The difference is documented in the recently added Result Location Semantics: Result Locations section of the language reference.

My understanding is that

var foo: T = .{ .a = 1, .b = 2 };

is semantically equivalent to

var foo: T = .{};
foo.a = 1;
foo.b = 2;

and that

var foo = T{ .a = 1, .b = 2 };
// or
var foo = @as(T, .{ .a = 1, .b = 2 });

is semantically equivalent to

const temp: T = .{};
temp.a = 1;
temp.b = 2;
var foo = temp;

In other words, the former operates directly on the result variable while the latter creates a temporary variable, initializes it completely and then copies the result over to the result variable.

When initializing a completely new variable there will be no difference between the two, but when reassigning based on the previous value of the variable it does make a difference:

var foo: T = .{ .a = 1, .b = 2 };
foo = .{ .a = foo.b, .b = foo.a }; // .{}
assert(foo.a == 2);
assert(foo.b == 2);

var bar: T = .{ .a = 1, .b = 2 };
bar = T{ .a = bar.b, .b = bar.a }; // T{}
assert(bar.a == 2);
assert(bar.b == 1);

As a side note, because T{} and @as(T, .{}) are equivalent, it is possible that the T{} syntax will be removed in the future.

@castholm is completely correct – the only difference is the application of RLS. For most purposes, these syntax forms are equivalent.

Broadly speaking, .{ ... } is the preferred syntax. As mentioned above, it is possible that T{ ... } will be removed in the future. The few places where official documentation uses this syntax are probably just outdated, and thus don’t conform to today’s conventions.

Thanks for the quick replies, both of you. Especially the link to the RLS documentation @castholm, that cleared up a lot of things.

So the anonymous struct syntax is prefered as long as I’m not modifying things in place in a way that depends on the previous value of the struct?