Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Concept for reducing the verbosity of generics #1419

Open
jimy-byerley opened this issue Jun 24, 2024 · 0 comments
Open

Concept for reducing the verbosity of generics #1419

jimy-byerley opened this issue Jun 24, 2024 · 0 comments

Comments

@jimy-byerley
Copy link

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. 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<T,R,C> as a trait with type and shape arguments, 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 rather than trait arguments: Matrix<Element=T, Rows=R, Columns=C> 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 as recommended for such issue. making struct Matrix(array) a wrapper.

key concepts

The Matrix type is only a wrapper of its array storage, 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 it is not able to detect that Matrix<SomeTrait<R=Dyn>> is different from Matrix<SomeTrait<R=Const>> giving that Dyn and Const are types.
    • Whereas currently in nalgebra it is able to detect that Matrix<T,Dyn,...> is different than Matrix<T,Const,...>

    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 !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant