Fundamentals 7 min read

Push Ifs Up, Push Fors Down: Improving Code Clarity and Performance

The article explains Alex Kladov’s two simple yet powerful rules—moving conditional checks out of functions and pushing loop bodies down—to reduce duplicated checks, simplify control flow, and boost performance, especially in batch‑processing scenarios.

Java Tech Enthusiast
Java Tech Enthusiast
Java Tech Enthusiast
Push Ifs Up, Push Fors Down: Improving Code Clarity and Performance

Many programmers wonder whether a condition should be placed inside a function or outside, and whether an if should be added inside a loop. Alex Kladov’s “Push Ifs Up, Push Fors Down” rules address these questions by advocating that condition checks be performed as early as possible and that bulk processing be performed in outer loops.

Push Ifs Up

If a function contains an if that validates its arguments, consider moving that check to the caller so the function can focus on its core work. This eliminates duplicated pre‑condition checks, reduces branching inside the function, and makes the overall program easier to read.

// Good version
fn frobnicate(walrus: Walrus) {
    ...
}

// Bad version
fn frobnicate(walrus: Option
) {
    let walrus = match walrus {
        Some(it) => it,
        None => return,
    };
    ...
}

By centralising validation, you avoid repeated if statements scattered across many functions, which can hide dead code and make debugging harder.

Example of duplicated branching:

fn f() {
    if foo && bar {
        if foo {
        } else {
        }
    }
}
fn g() {
    if foo && bar {
        h()
    }
}
fn h() {
    if foo {
    } else {
    }
}

Moving the outer condition out of the inner loops makes the unnecessary branches obvious.

Push Fors Down

When processing many items, handle the batch at the highest level instead of iterating over each element and performing the same work individually. This reduces loop overhead, enables vectorised or bulk optimisations, and often yields dramatic speed‑ups.

// Good version
frobnicate_batch(walruses)

// Bad version
for walrus in walruses {
    frobnicate(walrus)
}

Batch processing also aligns with data‑oriented design, allowing you to amortise start‑up costs and reorder operations for better cache utilisation. An illustrative example is using FFT to multiply many polynomials simultaneously rather than one‑by‑one.

Combining the two rules yields even cleaner code:

// Good version
if condition {
    for walrus in walruses {
        walrus.frobnicate()
    }
} else {
    for walrus in walruses {
        walrus.transmogrify()
    }
}

// Bad version
for walrus in walruses {
    if condition {
        walrus.frobnicate()
    } else {
        walrus.transmogrify()
    }
}

This arrangement avoids repeated condition checks inside the loop, improves readability, and can unlock further compiler optimisations such as vectorisation.

In summary, moving if statements outward and pushing for loops inward leads to clearer, more maintainable code and measurable performance gains.

Performancerustsoftware engineeringBest Practicescode qualityrefactoring
Java Tech Enthusiast
Written by

Java Tech Enthusiast

Sharing computer programming language knowledge, focusing on Java fundamentals, data structures, related tools, Spring Cloud, IntelliJ IDEA... Book giveaways, red‑packet rewards and other perks await!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.