Skip to content

S27: Outdated idioms

S27Severity: Low

Old patterns that the current standard library or edition replaces.

Clippy: legacy_numeric_constants, manual_map, non_std_lazy_statics, uninlined_format_args

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
  • 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_static was the standard answer for a global map for many years.
  • Extra dependencies. lazy_static and once_cell are now in std. Each crate is code to audit and update. See S28: Too many or unknown dependencies.
  • More code to read. A manual match that rebuilds an Option is five lines where .map is 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, try is a reserved keyword, so try! must be written r#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.

  1. Worselazy_static, a manual Option match with ref, 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)
    }
  2. BetterLazyLock from std, HashMap::from with 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.80
    pub 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.

  • A crate with an old minimum Rust version (MSRV). A library that must build on Rust 1.70 cannot use LazyLock. Then once_cell is the right choice. Check rust-version in Cargo.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.
  • Clippy, on by default: legacy_numeric_constants (style) reports std::u64::MAX, and manual_map (style) reports the match. The compiler warns that std::u64::MAX is deprecated.
  • Clippy pedantic group: non_std_lazy_statics reports lazy_static!, and uninlined_format_args reports format!("{}", x).
  • cargo fix --edition updates code to the next edition. Read the edition guide first.
  • In Cargo.toml, look for lazy_static, once_cell, failure, and a missing or old edition.
Use current Rust idioms for edition 2024: std::sync::LazyLock instead of
lazy_static or once_cell, the ? operator, Option and Result combinators such
as map instead of a match that rebuilds the value, u64::MAX instead of
std::u64::MAX, and inline format arguments such as format!("{name}"). Do not
use 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.