CodeBlanks Logo Icon CodeBlanks

Cost of abstraction

Learn how to measure the cost of abstraction.

The cost of abstraction

Rust's design principle, inherited from C++, is the zero-cost abstraction: "What you don't use, you don't pay for; what you do use, you couldn't hand-code any better." Abstractions like iterators, closures, generics and Option compile into the same machine code as a hand-written loop:

// abstract
let a: u32 = (1..=10).filter(|n| n % 2 == 0).sum();

// by hand
let mut b = 0;
let mut i = 1;
while i <= 10 {
    if i % 2 == 0 { b += i; }
    i += 1;
}

In a release build the two versions usually produce identical or nearly identical assembly.

Measuring

Verify claims by measuring. The criterion crate does statistical benchmarks; to see the assembly, use Compiler Explorer (godbolt.org) or cargo asm:

// benches/toplam.rs (criterion)
c.bench_function("yineleyici", |b| {
    b.iter(|| (1..=black_box(1000u32)).filter(|n| n % 2 == 0).sum::<u32>())
});

Zero cost doesn't hold for every abstraction: Box<dyn Trait>, Rc, RefCell and Mutex are deliberately chosen tools with a real cost.

Practice Two ways, same result

Compute the sum of the even numbers from 1 to 10 first with an iterator chain, then with a while loop. Print both results separated by a space.

Starter code

main.rs
fn main() {
    // buraya yaz
}

Sample solution

main.rs
fn main() {
    let a: u32 = (1..=10).filter(|n| n % 2 == 0).sum();
    let mut b = 0;
    let mut i = 1;
    while i <= 10 {
        if i % 2 == 0 {
            b += i;
        }
        i += 1;
    }
    println!("{} {}", a, b);
}

Expected output

30 30

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 Which build does the zero-cost claim apply to?

  • The optimized (release) build Correct answer
  • The debug build
  • Both equally
  • Neither

Explanation: In a debug build there's no inlining; abstractions really stay as function calls and are slow.

2 Abstract sum

Question
let a: u32 = (1..=10).____(|n| n % 2 == 0).sum();
Answer
let a: u32 = (1..=10).filter(|n| n % 2 == 0).sum();

Explanation: filter selects the even numbers; sum adds them up.

3 Tool and its cost

Term Meaning
Yineleyici zinciri Zero cost
Generic fonksiyon Zero (code grows)
Box<dyn Trait> Indirect call
RefCell Runtime check

All lessons in Expert