boilerplate-recursion

A recursive walk over a type is written out by hand, arm by arm.

Group
Opportunities
Runs
Runs under ur report: ur report --rule boilerplate-recursion
Level
note
Reads
Every file
Fix
None: the shape of the shared walk, and its name, are a design choice

Why

These recursive functions match on the variants of a type, and most arms only recurse into the fields they bind, combining the results the same way each time, or do nothing. A generic walk over the type, written or derived once, would do what those arms do, leaving each function only the arms that do its own work. It reads every language whose grammar states its shapes in a Shapes.rsc; an advisory rule that ur report runs.

The fix, as Ur suggests it: write or derive one generic walk over the type, and keep only the arms that do their own work.

For agents

Before writing a recursive function that matches on every variant of a type, look for a generic walk over the type and override only the variants the function is about.

Example

src/filter.rs
pub enum Filter {
    And(Box<Filter>, Box<Filter>),
    Or(Box<Filter>, Box<Filter>),
    Not(Box<Filter>),
    Any(Vec<Filter>),
    Field(String, String),
}

pub fn mentions(filter: &Filter, name: &str) -> bool {
    match filter {
        Filter::And(left, right) | Filter::Or(left, right) => {
            mentions(left, name) || mentions(right, name)
        }
        Filter::Not(inner) => mentions(inner, name),
        Filter::Any(filters) => filters.iter().any(|filter| mentions(filter, name)),
        Filter::Field(field, _) => field == name,
    }
}
What Ur prints
$ ur report --rule boilerplate-recursion
opportunity[boilerplate-recursion]: `mentions` walks `Filter` by hand: 4 of 5 variants only recurse into the fields they bind (saves about 4 lines)
  --> ./src/filter.rs:10:5-17 match in `mentions`: 5 of 5 variants only recurse or do nothing
  = hint: write or derive one generic walk over the type, and keep only the arms that do their own work
1 opportunity saving about 4 lines in all

Try it in the playground →