Functions & Methods
Avoid boolean arguments (no-bool-args)
A boolean parameter that selects between two behaviors signals the function does two things. Split it into two functions or use a typed enum.
// Good — two separate functions
fn read(&self, buf: &mut [u8]) -> Result<usize> { ... }
fn read_nonblocking(&self, buf: &mut [u8]) -> Result<usize> { ... }
// Good — typed enum
enum ReadMode { Blocking, NonBlocking }
fn read(&self, buf: &mut [u8], mode: ReadMode) -> Result<usize> { ... }
// Bad — boolean argument
fn read(&self, buf: &mut [u8], blocking: bool) -> Result<usize> { ... }
See also: Clean Code, Chapter 3 “Flag Arguments”.
Use block expressions to scope temporary state (block-expressions)
Use block expressions when temporary variables are only needed to produce one final value. This keeps temporary state local and avoids leaking one-off names into outer scope.
// Good — intermediate values are scoped to the block
let socket_addr = {
let bytes = read_bytes_from_user(addr, len as usize)?;
parse_socket_addr(&bytes)?
};
connect(socket_addr)?;
// Bad — temporary variables leak into outer scope
let bytes = read_bytes_from_user(addr, len as usize)?;
let socket_addr = parse_socket_addr(&bytes)?;
connect(socket_addr)?;
Minimize nesting (minimize-nesting)
Minimize nesting depth. Code nested more than three levels deep should be reviewed for refactoring opportunities. Each nesting level multiplies the reader’s cognitive load.
Techniques for flattening nesting:
- Early returns and guard clauses for error paths.
let...elseto collapseif letchains.- The
?operator for error propagation. continueto skip loop iterations.- Extracting the nested body into a helper function.
The normal/expected code path should be the first visible path; error and edge cases should be handled and dismissed early.
pub(crate) fn init() {
let Some(framebuffer_arg) = boot_info().framebuffer_arg else {
warn!("Framebuffer not found");
return;
};
// ... main logic at the top level
}
See also: PR #2877.
Introduce explaining variables (explain-variables)
Break down complex expressions by assigning intermediate results to well-named variables. An explaining variable turns an opaque expression into self-documenting code:
// Good — intent is clear
let is_page_aligned = addr % PAGE_SIZE == 0;
let is_within_range = addr < max_addr;
debug_assert!(is_page_aligned && is_within_range);
// Bad — reader must parse the whole expression
debug_assert!(addr % PAGE_SIZE == 0 && addr < max_addr);
See also: The Art of Readable Code, Chapter 8 “Breaking Down Giant Expressions”; PR #2083 and #643.