Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Infer or choose a specialization

Inference matches the signature against the argument types. In first(&values), the parameter is &list[T] and the argument is &list[i64], so T is i64. When multiple arguments determine the same parameter, their types must agree. Unsuffixed literals in generic positions use their normal defaults (i64 or f64); another argument does not change them. Keep explicit type arguments when you want them to guide literals: sum_to[u16](5) is equivalent to sum_to(5u16).

Types must be determined from arguments, not the expected return type. For example, this function needs empty[u8]() because it has no input mentioning T:

def empty[T]() -> Result[list[T], AllocError]:
    []

def main() -> Result[(), AllocError | IoError]:
    values = empty[u8]()?
    print(values)?
    Ok(())
[]

An annotation on the receiving binding does not change that rule:

def empty[T]() -> Result[list[T], AllocError]:
    []

def main() -> Result[(), AllocError | IoError]:
    values: list[u8] = empty()?
    Ok(())
cannot infer type parameter `T` for `empty` from its arguments

Calls with the same concrete types share one compiled specialization, including recursive calls. Independent uses can specialize many different helpers, or the same helper for many types. The compiler separately limits how deeply one new specialization requires another, how many one generic function has, and how many are created in total. These are compile-time resource limits; generic calls add no runtime allocation. See specialization limits for the current bounds.