Constructors and Initialization

Rust has no constructor keyword. What it has is a stricter rule: every field must be initialized before the struct can be used. The new() function is simply the conventional way to centralize that initialization.

Uninitialized fields are a compile error

#![allow(unused)]
fn main() {
// ERROR: missing field `sp` in initializer of `Cpu`
let cpu = Cpu {
    v: [0; 16],
    i: 0,
    pc: 0x200,
    stack: [0; 16],
    // sp forgotten — does not compile
};
}

Unlike C, there is no garbage memory waiting to cause a crash at runtime. The compiler ensures every value is set before it is read.

Why new() exists

Without it, every caller has to know all the initial values:

#![allow(unused)]
fn main() {
// without new() — caller must know everything
let cpu = Cpu { v: [0;16], i: 0, pc: 0x200, sp: 0, stack: [0;16], memory: ..., display: ... };

// with new() — clean and encapsulated
let cpu = Cpu::new();
}

new() centralizes the default values in one place. If initialization logic changes — say, fonts need to be loaded into memory at startup — you change new() and nothing else.

The Default trait

Rust provides a Default trait for types with a natural "zero" value. It can be derived:

#![allow(unused)]
fn main() {
#[derive(Default)]
pub struct Cpu { ... }

let cpu = Cpu::default();
}

The limitation: #[derive(Default)] sets every field to its type's zero (0 for integers, false for booleans). For Cpu, this is wrong — pc must start at 0x200, not 0. So we write new() manually.

You can bridge both approaches by delegating:

#![allow(unused)]
fn main() {
impl Default for Cpu {
    fn default() -> Self {
        Self::new()
    }
}
}

This makes Cpu work with parts of the ecosystem that expect Default, while keeping the initialization logic in new().


In the emulator: Cpu::new() initializes PC to 0x200, zeroes all registers, and delegates to Memory::new() and Display::new(). Memory::new() also loads the 16 font sprites into RAM at address 0x000 — something Default could not express. See Font Sprites for why fonts must be in memory from the start.