Raw Identifiers

Raw identifiers allow you to use reserved keywords as names by prefixing them with r#. This is an escape hatch for a very specific situation.

The problem

When implementing the CXNN (RND) opcode, we use the rand crate to generate random numbers:

#![allow(unused)]
fn main() {
let rand: u8 = rand::thread_rng().r#gen();
}

Without r#, the compiler fails:

error: expected identifier, found reserved keyword `gen`
help: escape `gen` to use it as an identifier
    |
    rand::thread_rng().r#gen::<u8>();
                       ++

Why this happened

Rust introduced gen as a reserved keyword in the 2024 edition (for generator syntax). The rand crate published a .gen() method long before that edition existed.

When you use Rust 2024 and call .gen() from an older crate, there is a keyword conflict. The compiler tells you exactly what to do: prefix with r#.

Rust editions

Rust uses an edition system to introduce breaking language changes without breaking existing code:

EditionYearNotable changes
2015original
2018async/await, module improvements
2021closure capture improvements
2024latestgen keyword, among others

Each crate declares its edition in Cargo.toml. Crates with different editions coexist in the same project — Cargo compiles each with its own rules. That is why rand 0.8 (edition 2018, where gen is not a keyword) and our emulator (edition 2024, where it is) work together.

When to use raw identifiers

Almost never. If you are writing new code, choose names that are not keywords. Raw identifiers exist to avoid breaking code when Rust adds new keywords — a situation you encounter when calling a library method, not when naming your own things.


In the emulator: r#gen() appears once, in the CXNN opcode implementation. See RND — Random Numbers for the full implementation, and External Crates for how the rand crate is added to the project.