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:
| Edition | Year | Notable changes |
|---|---|---|
| 2015 | original | |
| 2018 | async/await, module improvements | |
| 2021 | closure capture improvements | |
| 2024 | latest | gen 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 theCXNNopcode implementation. See RND — Random Numbers for the full implementation, and External Crates for how therandcrate is added to the project.