S27: Outdated idioms
What it looks like
Section titled “What it looks like”lazy_static! { static ref VAT_PER_MILLE: HashMap<&'static str, u64> = { let mut m = HashMap::new(); m.insert("CH", 81); m.insert("DE", 190); m };}
pub fn vat_cents(country: &str, net_cents: u64) -> Option<u64> { match VAT_PER_MILLE.get(country) { Some(ref rate) => Some(net_cents * **rate / 1000), None => None, }}
pub fn describe(country: &str) -> String { let limit = std::u64::MAX; format!("{}: limit {}", country, limit)}This code compiles on Rust 1.99, and it works. Every part has a newer replacement:
| Old | Current | Since |
|---|---|---|
lazy_static! (a crate) |
std::sync::LazyLock |
Rust 1.80 |
match with Some(x) => Some(f(x)), None => None |
.map(f) |
always |
Some(ref rate) |
Some(rate) (match ergonomics) |
Rust 1.26 |
std::u64::MAX |
u64::MAX |
Rust 1.43 |
format!("{}", name) |
format!("{name}") |
Rust 1.58 |
try!(expr) |
expr? |
Rust 1.13 |
extern crate serde; |
nothing: dependencies in Cargo.toml are in scope |
edition 2018 |
edition = "2015" or no edition |
edition = "2024" |
Rust 1.85 |
Why AI agents produce it
Section titled “Why AI agents produce it”- Old code is a large part of the training data. Rust has been stable since 2015. Blog posts, answers, and crates from the first years use the idioms of that time.
- It still compiles. Rust keeps old code working, so nothing tells the agent that the pattern is old. Some old forms give a warning, many do not.
- Old tutorials.
lazy_staticwas the standard answer for a global map for many years.
Why it is a problem
Section titled “Why it is a problem”- Extra dependencies.
lazy_staticandonce_cellare now instd. Each crate is code to audit and update. See S28: Too many or unknown dependencies. - More code to read. A manual
matchthat rebuilds anOptionis five lines where.mapis one. - It is a signal. Code with old idioms was probably copied from old sources. Check its other parts, such as error handling and dependency versions, with more care.
- Edition problems. In edition 2018 and later,
tryis a reserved keyword, sotry!must be writtenr#try!. An agent that “fixes” that error makes the code worse, not better.
The severity is low. The old code is not wrong. It is harder to read and to maintain.
The better version
Section titled “The better version”Worse
lazy_static, a manualOptionmatch withref,std::u64::MAX, and positional format arguments.lazy_static! {static ref VAT_PER_MILLE: HashMap<&'static str, u64> = {let mut m = HashMap::new();m.insert("CH", 81);m.insert("DE", 190);m};}pub fn vat_cents(country: &str, net_cents: u64) -> Option<u64> {match VAT_PER_MILLE.get(country) {Some(ref rate) => Some(net_cents * **rate / 1000),None => None,}}pub fn describe(country: &str) -> String {let limit = std::u64::MAX;format!("{}: limit {}", country, limit)}Better
LazyLockfromstd,HashMap::fromwith an array,.map,u64::MAX, and inline format arguments.static VAT_PER_MILLE: LazyLock<HashMap<&str, u64>> =LazyLock::new(|| HashMap::from([("CH", 81), ("DE", 190)])); // in `std` since Rust 1.80pub fn vat_cents(country: &str, net_cents: u64) -> Option<u64> {VAT_PER_MILLE.get(country).map(|rate| net_cents * rate / 1000)}pub fn describe(country: &str) -> String {let limit = u64::MAX;format!("{country}: limit {limit}")}
The test both_versions_agree shows that both give the same results.
When it is acceptable
Section titled “When it is acceptable”- A crate with an old minimum Rust version (MSRV). A library that must build on Rust 1.70 cannot use
LazyLock. Thenonce_cellis the right choice. Checkrust-versioninCargo.toml. - Code that you do not change. Do not ask an agent to modernize a whole file in a change that has another purpose. A separate change is easier to review.
How to detect it
Section titled “How to detect it”- Clippy, on by default:
legacy_numeric_constants(style) reportsstd::u64::MAX, andmanual_map(style) reports thematch. The compiler warns thatstd::u64::MAXis deprecated. - Clippy
pedanticgroup:non_std_lazy_staticsreportslazy_static!, anduninlined_format_argsreportsformat!("{}", x). cargo fix --editionupdates code to the next edition. Read the edition guide first.- In
Cargo.toml, look forlazy_static,once_cell,failure, and a missing or oldedition.
What to tell your agent
Section titled “What to tell your agent”Use current Rust idioms for edition 2024: std::sync::LazyLock instead oflazy_static or once_cell, the ? operator, Option and Result combinators suchas map instead of a match that rebuilds the value, u64::MAX instead ofstd::u64::MAX, and inline format arguments such as format!("{name}"). Do notuse extern crate. Remove dependencies that the standard library replaces.Run cargo clippy with the pedantic group to find the rest.Related: S28: Too many or unknown dependencies, S26: Hallucinated crate, API, or feature flag, Modules, crates, and Cargo, and Macros.