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

Generic function values

A higher-order function can use a type parameter inside its callable signature. The compiler infers the type from the function value and the other arguments:

def increment(value: u8) -> Result[u8, OverflowError[u8]]:
    Ok(value + 1)

def apply[T, U](operation: Callable[[T], U], value: T) -> U:
    operation(value)

def main() -> Result[(), IoError | OverflowError[u8]]:
    print(apply(increment, 41u8)?)?
    Ok(())
42

Here T is u8. Passing 41i64 would conflict with increment’s signature.

To choose a generic function’s own type arguments, use brackets without calling it:

def identity[T](value: T) -> T:
    value

def main() -> Result[(), IoError]:
    keep = identity[u8]
    print(keep(42))?
    Ok(())
42

identity[u8] is a function value; identity[u8](42) calls that specialization.

A concrete callable annotation can also supply those type arguments:

def identity[T](value: T) -> T:
    value

def main() -> Result[(), IoError]:
    keep: Callable[[u8], u8] = identity
    print(keep(42))?
    Ok(())
42

This also works when a parameter or return type supplies the concrete signature. Without that context, use explicit brackets such as identity[u8].