Course contentsShow
← Rust
Lesson 782 of 1,9106. Generics and Static DispatchFree lesson

Performance Budgets for Generic Bloat

Establish metrics to decide when to split a large generic function into smaller, discrete units.

In this lesson, you will learn how to set quantitative metrics to decide when a generic function has become too "heavy" and needs to be split.

When we use generics, the compiler performs monomorphization—generating a unique copy of the function for every concrete type used. While this provides excellent runtime performance, it creates "code bloat." If a function grows too large, this duplication significantly increases binary size and strains the instruction cache, eventually slowing down your program instead of speeding it up.

Establishing Your Budget

To manage this, we use a simple performance budget based on two metrics: Function Complexity and Monomorphization Fan-out.

  1. Complexity: If a generic function contains logic unrelated to the generic type (e.g., logging, heavy IO, or data transformation), that logic is being duplicated unnecessarily.
  2. Fan-out: How many distinct types call this function? If you have 50 different types invoking a 100-line generic function, you are effectively adding 5,000 lines of machine code to your binary.

The Splitting Strategy

The rule of thumb is: Isolate the generic "hot path" from the non-generic "cold path."

Consider this bloated example:

fn process_data<T: DataTrait>(item: T) {
    // Heavy non-generic setup logic
    let config = load_global_config(); 
    let logger = setup_logger();
    
    // The actual generic core
    item.transform(); 
    logger.log("Success");
}

The load_global_config and logger logic are duplicated for every type T. By refactoring, we keep the binary slim:

fn process_data<T: DataTrait>(item: T) {
    // Extract non-generic logic to a standard function
    perform_setup(); 
    
    // Keep only the generic core here
    item.transform(); 
}

fn perform_setup() { /* Shared across all types */ }

By moving non-generic code into small, shared functions, you ensure that even if you have hundreds of generic instantiations, the compiler only copies the minimal, type-dependent logic. If your generic function exceeds 20-30 lines of code, it is time to move the "cold" logic into non-generic helper functions.

Key Takeaway: To curb generic bloat, keep generic functions focused strictly on type-dependent operations and move all common, non-generic logic into shared, standard functions.