dimforge / dimforge/nalgebra

Concept for reducing the verbosity of generics

Open
#1,419 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
4.8k
Forks
565
PR merge metrics
No merged PRs in 30d

Description

# Concept for reducing the verbosity of generics

Hello nalgebra maintainers
This weekend I have been doing some experiments in designing a matrix structure with the same goals as nalgebra's (static & dynamic arrays, small & large dimensions, ergonomics ...) but with the less possible verbosity due to generics. (I must admit I often have been bored by the complexity of specifying generics before starting implementing a generic function using nalgebra)

I ended up in a good proof of concept, I called [flexalgebra](https://github.com/jimy-byerley/flexalgebra). For the moment it only has implementations for scalar, elementwise and matrix operations for all the type of matrices and vectors and their constructors. I assume they are the most relevant operations for what I'm talking about.

I share it with you in case it might be of some use. I would be very interested in having your opinion anyway

## failed concepts

I started defining `Matrix` [as a trait with type and shape arguments](https://github.com/jimy-byerley/flexalgebra/blob/94708fbd966dde43341361d2f4500e952499ec26/src/matrix.rs#L9), so any crate could implement it on array structures and benefit from all matrix methods and traits implementations, and compatibility with other matrices. It did not worked for obvious reasons: the trait matrix could be implemented multiple times for the same struct

I then defined the [type and shape as trait attributes](https://github.com/jimy-byerley/flexalgebra/blob/a34882c3fe8083706d86546ea2709f499a442939/src/matrix.rs#L9) rather than trait arguments: `Matrix` so without arguments the trait could be implemented only once. It did not worked either for obvious reasons: implementing foreign traits like `Index` or `Mul` on possibly foreign types is not allowed.

So I adopted the [newtype pattern](https://doc.rust-lang.org/rust-by-example/generics/new_types.html) as recommended for such issue. making `struct Matrix(array)` a wrapper.

## key concepts

The [`Matrix` type is only a wrapper](https://github.com/jimy-byerley/flexalgebra/blob/44bdd65d8b332929a4ab8491aa90a2f99edaeda6/src/matrix.rs#L29) of its [array storage](https://github.com/jimy-byerley/flexalgebra/blob/44bdd65d8b332929a4ab8491aa90a2f99edaeda6/src/matrix.rs#L36), a bit like currently in `nalgebra` but without any generic parameters or additional private fields

Being a wrapper has many advantages for the matrix struct:

- it takes nothing to create and destroy
- it can eventually wrap any user array type
- it doesn't add too much verbosity to the definition of the underlying type

Without any generics, this type wrapper rely only on the genericity of its underlying array. The matrix properties then only depends on the traits implemented by this array. In a way `nalgebra` does this, but at the same type keeps generics at the matrix level, generating lot of clauses to make a matrix compatible with its array.

For the array traits, I set the generics also as attributes rather than parameters. This allows to omit these parameters and mention them in generics clauses only when we need to constrain them. This way writing code with high degree of genericity (with less constraints on generics) is very simple. This is the point that greatly simplified my library.

## limitations

This concept brings two minor limitations to what nalgebra currently does:

- array storage types cannot implement array traits multiple types (because traits are using attributes rather than parameters), but who needs that ?

- `Matrix` type cannot specialize according to dimensionalities:

- Since rust's current trait solver [does not detect exclusive traits](https://users.rust-lang.org/t/methods-implemented-for-specialized-structs-are-said-duplicates-when-specializing-over-exclusive-traits/113315) it is not able to detect that `Matrix>` is different from `Matrix>` giving that `Dyn` and `Const` are types.
- Whereas currently in nalgebra it is able to detect that `Matrix` is different than `Matrix`

So in flexalgebra there can be only one method or trait implementation for dimensions and types, as long as the array storage type is generic.

It is a bit bothering because it requires to implement matrix constructors specifically for each matrix type. But I think this is not a great limitation since most methods are fully generic and other could be named differently according to dimensionality

This raises however the following limitations compared to nalgebra:

- no more need to specify 10 generics in each function impl
- very easy to implement array storage traits for user types

In addition the core set of structs and traits defining a matrix becomes minimalistic, which is good I think !

## conclusion

I know that nalgebra is already well diffused and complete, I do not ask any of this to land one day in nalgebra. Even though I would appreciate an improvement regarding the initial verbosity concerns . This is just a proof of concept for reducing this concern.

Check the code, tell me what you think !

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.