Struct initialization, order of evaluation

Tuples are guaranteed to be initialized in order. How about structs?

Doing some marshalling. So I have things like

let vector3d = Vector3d{x: getnextvalue(); y: getnextvalue(); z: getnextvalue()};

where "getnextvalue()" is reading a value from some stream and thus has side effects.

How about the nested case?

let place = Place(pos:  Vector3d{x: getnextvalue(); y: getnextvalue(); z: getnextvalue()),
                         rot: Quaternion(x: getnextvalue(); y: getnextvalue(); z: getnextvalue(), s: getnextvalue()));

If this doesn't work, I have to generate a huge number of in-order "let foo = ..." followed by struct initializers to put the pieces together. Ugly, but do-able.

So, is this well-defined, or is it undefined behavior? And is it the order of the named fields in the intializer, or the order of the named fields in the struct, which matters? Thanks.

Reddit discussion four years ago indicated this worked but maybe could not be relied upon.

It should be left-to-right.

But is that guaranteed? Could it change through some optimization? There's potential there for obscure optimizer-related bugs if this is undefined behavior.

They are created in the order you've written the initialization, and this is de facto guaranteed. There has been discussion about formalizing this guarantee, but IIRC the sense is that too much is already relying on this to change it now.

If initialization is interrupted in any way (e.g. return from an expression or panics) the partial fields will be dropped in reverse of the order you've written. Once the struct is complete, dropping fields happens in order of the struct declaration.

1 Like

See also:

3 Likes

It is definitely not undefined behavior in any case. You can't have UB without an unsafe block.

2 Likes

OK. Consensus seems to be that 1) it works left to right, 2) nothing in the spec absolutely guarantees this, and 3) it's come up a few times. So I updated the item on Github to ask for a documentation fix.

We don't want someone writing a code generator thinking "Oh, order doesn't matter there and we can save an instruction by initializing in reverse order".

Thanks. I'll go with big initialization expressions.

1 Like

The issue is already asking for a documentation fix. Posting on it just reminded me it existed, but didn't actually add anything new to the story. As already stated, the order is already fixed since it's already relied on by other code. And changes to rustc are also tested against the entirety of crates.io for breaking changes by stuff like that...

There's also a PR for fixing that issue, though since I forgot I filed it, I didn't actually link them together.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.