Skip to content

Generic functions

Masahiro Sakuta edited this page Aug 5, 2024 · 1 revision

Generic function ideas

Currently this is just idea sketch for generic functions.

Generic properties

One interesting lesson from Rust's type system is that generic functions doesn't have to put types that modifies the generated code. For example, Rust's lifetime always show up as generics in the code (except 'static), but it does not generate many copies of the machine code for each concrete lifetime.

A contrived example is given below. The first_3 function returns first 3 bytes of a given slice, so the returned string slice has the same lifetime as the argument.

fn first_3<'a>(s: &'a str) -> &'a str {
    &s[..3]
}

However, this 'a does not affect the function implementation at all. It is merely a signal to the compiler that the returned reference (string slice in this case) has some specific lifetime in relation to another, so that the calling code should be borrow-checked accordingly. The compiler is free to generate a single copy of this function and use it for all occurrences of first_3, even if the actual lifetime varies among calls.

Similarly, we can think of generic parameters to define the shape of an array, and tell the compiler that the returned value has some (maybe different) shape in relation to input. You can imagine a function like below (the generic syntax is inspired by Rust, but probably should be simpler).

fn transpose<T, const n: usize, const m: usize>(array: [T; n, m]) -> [T; m, n];

This type signature tells that the output's number of rows and colmns are swapped from the inputs. It suggests the functionality of the function, but more importantly, make type checker work for compile-time known array shapes.

We could imagine more useful functions, for example, reshape function would be defined like below. The generic parameters n and m could be inferred from the second argument, if it is a constant expression.

fn reshape<T, const n: usize, const m: usize>(array: [T], [n, m]: [u64; 2]) -> [T; n, m];

We probably would need function overloading to allow dynamic shapes to use this function.

fn reshape<T>(array: [T], shape: [u64; 2]) -> [T; .., ..];
Clone this wiki locally