What is the evaluation order of tuples in Rust?
Asked Answered
M

1

11

Tuple elements may have side-effects, and some of them may depend on others. Consider this program:

fn main() {
    let mut v = vec![1, 2];
    match (v.pop(), v.pop()) {
        (Some(z), Some(y)) => println!("y = {}, z = {}", y, z),
        _ => unreachable!(),
    }
}

Does it output y = 1, z = 2 or y = 2, z = 1? A few rounds on the Rust Playground suggests the former on stable 1.32.0, but maybe it would change if I ran it more times, recompiled the compiler, changed compiler versions, etc.

Is there a documented commitment or at least intention to maintain a particular order of evaluation for tuples (e.g. depth-first and left-to-right)?

Moorman answered 22/1, 2019 at 17:16 Comment(0)
D
14

Yes, the order of evaluation for tuples is guaranteed to be left-to-right (which also implies depth-first, as the value must be fully constructed).

Unfortunately, this is never stated explicitly anywhere that I can find, but can be inferred from Rust's strong backwards compatibility guarantees. Making a change to evaluation order would likely introduce far too much breakage to ever be seriously considered.

I'd also expect that the optimizer is allowed to make changes when safe to do so. For example, if the expressions in the tuple have no side effects, then reordering them is invisible to the user.

See also:

Deibel answered 22/1, 2019 at 17:30 Comment(2)
Thanks, this seems to be a common enough pattern in the compiler itself so I won't feel too bad about repeating it. rg "match \(.*,.*\(\)" turned up some examples including this match in src/libserialize/json.rs.Moorman
Tuple element ordering is preserved in translation to HIR. Then after translation from HIR to HAIR tuples may be evaluated left-to-right to produce a MIR Rvalue.Moorman

© 2022 - 2024 — McMap. All rights reserved.