Tuples

When implementing the arithmetic opcodes, we run into a situation where a single operation produces two pieces of information that are equally important: the result of the calculation, and whether it overflowed. In most languages you would use an output parameter or a struct. In Rust, the idiomatic answer is a tuple.

What is a tuple?

A tuple groups a fixed number of values that can have different types:

#![allow(unused)]
fn main() {
let pair:   (u8, bool)      = (255, true);
let triple: (u8, u16, bool) = (10, 300, false);
}

Unlike arrays, each position can hold a different type. The type of the tuple is part of the type signature — (u8, bool) and (u16, bool) are different types.

You can access elements by index:

#![allow(unused)]
fn main() {
let pair = (0x42u8, true);
let value = pair.0;  // 0x42
let flag  = pair.1;  // true
}

But in practice, nobody writes .0 and .1. The idiomatic approach is to unpack immediately.

Destructuring: the way you actually use tuples

#![allow(unused)]
fn main() {
let (result, carry) = self.v[x].overflowing_add(self.v[y]);
}

overflowing_add returns (u8, bool). Destructuring pulls both values out in a single line and gives each a clear name. Compare this to the alternative:

#![allow(unused)]
fn main() {
let pair     = self.v[x].overflowing_add(self.v[y]);
let result   = pair.0;
let carry    = pair.1;
}

Same information, three times more noise. Destructuring is not just shorter — it makes the intent clearer at the point where the variable is introduced.

Returning multiple values from a function

Tuples are the standard way to return more than one value:

#![allow(unused)]
fn main() {
fn divide(a: u8, b: u8) -> (u8, u8) {
    (a / b, a % b)
}

let (quotient, remainder) = divide(10, 3);
}

There is no "out parameter" in Rust. If a function needs to communicate multiple results, it packs them into a tuple (or a struct, if the values deserve names at the definition site).

The unit type: ()

An empty tuple () is called the unit type. It represents the absence of a meaningful value — the equivalent of void in other languages. Functions that do not explicitly return anything implicitly return ().


In the emulator: Tuples appear in the 8XY4 (ADD with carry) and 8XY5 (SUB with borrow) opcodes, where overflowing_add and overflowing_sub return (value, bool). The bool is then stored in VF. See 8XY* — Arithmetic and Logic. The destructuring syntax used with tuples is explored further in Destructuring.