Structs and impl Blocks
Rust has no classes. The equivalent is a struct for data and an impl block for methods — kept deliberately separate.
The struct
A struct is a named group of fields:
#![allow(unused)] fn main() { pub struct Cpu { pub v: [u8; 16], // general-purpose registers V0–VF pub i: u16, // index register pub pc: u16, // program counter pub sp: u8, // stack pointer pub stack: [u16; 16], // return address stack } }
Each field has a name and a type. pub makes a field visible outside the module — without it, the field is private by default.
The impl block
Methods live in a separate impl block:
#![allow(unused)] fn main() { impl Cpu { pub fn new() -> Self { Cpu { v: [0; 16], i: 0, pc: 0x200, // programs start at 0x200 sp: 0, stack: [0; 16], } } pub fn step(&mut self) { // fetch, decode, execute one instruction } } }
new() is a static constructor — it takes no self. step() takes &mut self because it modifies the CPU state.
&self vs &mut self
This distinction is enforced at compile time:
&self— read-only access to the struct's fields&mut self— read and write access
If a method with &self tries to modify a field, the compiler rejects it. This prevents accidental mutations and is part of Rust's core ownership system.
OOP comparison
| OOP | Rust |
|---|---|
| class | struct + impl |
| constructor | new() (convention, not a keyword) |
| method | function in impl |
this / self | &self or &mut self |
| inheritance | doesn't exist — use Traits |
| private/public | pub per item |
Why separate data from behavior?
It makes each concern independently visible. Looking at a struct, you see exactly what data it holds. Looking at an impl, you see exactly what it can do. You can have multiple impl blocks — useful for putting tests in a separate file — and you can implement traits in their own blocks.
In the emulator:
Cpu,Memory, andDisplayare all structs with their ownimplblocks.Cpuowns aMemoryand aDisplayas fields. The CHIP-8 Registers chapter describes what each field ofCpurepresents in hardware terms. The Constructors chapter explains whynew()is needed forCpuspecifically.