# Integrating const-generics to nalgebra 0.26

Today we released the version 0.26 of our general-purpose linear-algebra crate: **nalgebra** ðŸŽŠ

The version 1.51.0 of Rust has been released
three weeks ago. That version stabilized an MVP for one of the feature we wanted the most: **const-generics**.
Const-generics allow you to define types parametrized by const integers, chars, or booleans. One iconic
example is writing a structure wrapping an array of any size:

**nalgebra** supports matrices (and vectors) with dimensions known at runtime or at compile-time.
The components of matrices/vectors with dimensions known at runtime are stored in a `Vec<T>`

.
Before **nalgebra 0.26**, matrices/vectors with dimensions known at compile-time were stored
in a `GenericArray`

, from the excellent generic-array
crate. Thanks to const-generics, we were able to replace `GenericArray`

by standard arrays: `[[T; R]; C]`

(where `R`

is the number of rows, and `C`

the number of columns) in **nalgebra 0.26**.

This change results in significant ergonomics improvements when using statically-sized matrices or vectors:

### 1. Simpler generic programming with statically-sized entities

Using **nalgebra** for generic programming with statically-sized
matrices/vectors/points was quite challenging before. Let's take a
simple example of a generic structure that wraps a point, a vector,
and a matrix and performs some kind integration using 64-bit precision.
In previous version of **nalgebra** this would look like this:

See all the `DefaultAllocator: Allocator<...>`

trait bounds? They are here to help the compiler
deduce the proper storage types for the matrix/vector/points (i.e. to deduce the `GenericArray`

with the right dimensions).

Now that const-generics have been integrated to **nalgebra** this code becomes as simple
as one would expect:

See that there isn't any `DefaultAllocator: Allocator`

trait bounds whatsoever.

Now, keep in mind that these simplifications will only work if you stick with entities
with dimensions known at compile-time. If your code needs to work generically for both
statically-sized matrices and dynamically-sized matrices, then the `DefaultAllocator: Allocator`

bounds are still necessary (we should be able to get rid of them too once **specialization**
is stabilized).

### 2. Simpler debugging of small matrices and vectors

This one is a life-changer for those relying extensively on debuggers. Until now,
inspecting with a debugger the content of statically-sized matrices or vectors (or
points, quaternions, etc.) was extremely difficult. This was caused by the smart,
but complicated, recursive definition of `GenericArray`

. Here is what inspecting
the content of `let matrix = Matrix2::new(1, 2, 3, 4)`

looked like (in CLion's debugger,
using the Rust plugin):

Here is what it looks like now that we replaced `GenericArray`

by standard arrays:

This is much clearer now. Keep in mind that **nalgebra** stores its matrices in
column-major format. That's why the components appear in the order `[[1, 3], [2, 4]]`

(column
by column).

### 3. Building small, constant, matrices and vectors

Now that small matrices are using standard arrays under the hood, it is now possible
to define constant vectors, matrices, points, quaternions, and translations by using
their `const fn new(...)`

constructors:

### 4. New aliases

Everything in **nalgebra** ends up being expressed as a matrix, in one way or another. Even
a vector is just the `Matrix`

type setup to have only one column. This is why we have so many
type aliasses like `Vector3`

which is an alias for a matrix with 3 rows and one column.

In **nalgebra 0.26** we have the following dimension-generic type aliases:

`OMatrix<T, R: Dim, C: Dim>`

: for owned matrices (formerly called`MatrixMN`

), i.e., matrices that own their components (as opposed to matrix slices that borrow them).`SMatrix<T, const R: usize, const C: usize>`

: for statically-allocated matrices.`DMatrix<T>`

: for dynamically-allocated matrices.

All the aliases for specific dimensions (e.g. `Vector3`

for 3D vectors) remain unchanged.

The same applies to vectors: `OVector, SVector, DVector`

. For example a statically-sized vector
with 528 components can be written `SVector<f32, 528>`

.

`typenum`

is still needed

Limitations: why We no longer use the `generic-array`

crate, but you will notice that **nalgebra** continues
to depend on the `typenum`

crate. This is needed because const-generics support on Rust 1.51
isn't complete yet, and doesn't allow operations on the const-parameters like in the following
`push`

method that adds an element to an array:

In order to overcome this limitation, we have to rely on `typenum`

by converting the
integer to a type-level-integer, performing the operation with `typenum`

's type-level operators,
and then extracting the result as a const value. This roughly looks like this:

It's actually less verbose in **nalgebra** because we have some additional traits to hide some
of the complexity going on here. But the fact remains that without more advanced const-generics
support from the compiler, methods like this `push`

will be more verbose to define, and will be limited
to the values of `D`

(currently the values in `[0, 127]`

) such that `Const<D>: TyTypenum`

is implemented.

## What's next?

The const-generics MVP allowed us to significantly improve the ergonomics of statically-sized
matrices and vectors. However, we are still waiting for two features to land to make
**nalgebra** much nicer:

**Specialization**: with specialization in place, we could get rid of all the`DefaultAllocator: Allocator<...>`

bounds. This means writing generic code that accepts both statically-sized matrices and dynamically-sized matrices would become much easier.**Const-generics**(the complete version): being able to write something like`[T;Â {Â LENGTHÂ +Â 1Â }]`

would allow us to remove the`typenum`

dependency completely.**Const-fn**(the complete version): being able to have trait bounds other than`Sized`

in generic const-functions would allow us to mark most of**nalgebra**'s methods as`const`

. Right now, only some constructors are possible.