ferrule documentation[styled mode]
specrfcshome

RFC-0003

const generics

Status: draft | Target: α2


RFC-0003: const generics

summary

const generics allow type parameters to include compile-time constant values, enabling fixed-size arrays, matrices, and other parameterized-by-value types.

motivation

currently, arrays in ferrule must have their size specified at the type level with a literal:

const buffer: Array<u8, 1024> = [...];

there's no way to write a function that works with arrays of any size:

// we want this, but can't express it today
function sum<const N: usize>(arr: Array<i32, N>) -> i32 { ... }

const generics enable:

detailed design

syntax

const parameters use the const keyword in the generic parameter list:

type Matrix<T, const ROWS: usize, const COLS: usize> = {
  data: Array<Array<T, COLS>, ROWS>,
};

function zeros<const ROWS: usize, const COLS: usize>() -> Matrix<f64, ROWS, COLS> {
  return Matrix {
    data: [[0.0; COLS]; ROWS],
  };
}

const m: Matrix<f64, 3, 4> = zeros();

allowed const types

const parameters can be any of these types:

const expressions

const parameters can use expressions that are evaluable at compile time:

type AlignedBuffer<const SIZE: usize> = {
  data: Array<u8, align_up(SIZE, 64)>,
};

function align_up(size: usize, alignment: usize) -> usize {
  return (size + alignment - 1) & ~(alignment - 1);
}

the expression must be evaluable with only const inputs.

inference

const parameters can be inferred from usage:

function length<T, const N: usize>(arr: Array<T, N>) -> usize {
  return N;
}

const arr = [1, 2, 3, 4, 5];
const len = length(arr);  // N inferred as 5

constraints

const parameters cannot use where clauses in α2. this is future work:

// future: const constraints
function safe_divide<const D: i32>(n: i32) -> i32
  where D != 0
{
  return n / D;
}

monomorphization

each unique combination of const parameters creates a separate monomorphized function:

const a = zeros<2, 3>();  // generates zeros_2_3
const b = zeros<4, 4>();  // generates zeros_4_4

drawbacks

alternatives

macros instead of const generics

generate code with comptime macros:

comptime function make_matrix(rows: usize, cols: usize) { ... }

rejected because it doesn't provide the same type safety and ergonomics.

only literal sizes

require all sizes to be literals, no generics:

const arr: Array<i32, 10> = [...];

rejected because it prevents abstracting over array sizes.

prior art

languagefeature
rustconst N: usize in generics
c++non-type template parameters
zigcomptime parameters
dtemplate value parameters

rust's approach is most similar to this proposal. zig's comptime is more powerful but less explicit.

unresolved questions

  1. should we allow const parameters in where clauses?
  2. how do we handle const parameters in error messages?
  3. should const expressions support all operators or a subset?

future possibilities