Field defaults

std.Io.Mutex is intended to be initialized with a declaration literal:

my_mutex: Mutex = .init;

An alternative design would be to make the following work:

my_mutex: Mutex = .{};

And this is how it used to work.

What are the consequences of these different design choices? Why should I prefer one over the other?

1 Like

Default fields make sense when you can change fields independently of each other.
But if doing so can cause an invalid state, a declaration is preferred as it prevents that.

Declarations also provide a clear name to the state, there can be multiple, and can coexist with default fields.

2 Likes

But I guess in this case these two don’t really apply?

There’s just .init, and it is called .init, rather than .unlocked. And Mutex has just a single field internally.

1 Like

For that specific question, it shouldn’t be .unlocked because a user shouldn’t do, for example:

my_lock.lock();
defer my_lock = .unlocked;

That is, .init should only be used for initialization, so it is named as such.

In general, it seems the consensus of the core team is that default fields are only the way to do things in a few specific cases, and initialization of variables tends to not be one of them. The main “rule” is that you should not use default fields if setting one of the fields but not another has the potential for the struct to be initialized in an invalid state. This has cascaded in a general style change of using decl literals for “default” initialization across the std, which includes the mutex. Another advantage is that this gives an explicit API surface point of “this is how you initialize this” instead of just knowing that an empty initialization (.{}) is a usable construct.

As far as I understand it, the only reason default field values are still in the language at all is because they’re really useful for options structs.

6 Likes

Something that might remove the need for defaults is if you could do .default with .{ .foo = 10 }. I’m not sure the caveats and footguns of a system like that, but in the very least it’s trivially implementable in userspace.