Generics with 0.11 become really hard
- Dominant language
- Rust
- Stars
- 4.8k
- Forks
- 565
- PR merge metrics
- No merged PRs in 30d
Description
I might be missing some new trait that might make this easier but things seem to have got really complicated when using generics and nalgebra 0.11
I have code like this in 0.10:
extern crate nalgebra;
extern crate num;
```rust
use nalgebra::*;
pub fn bezier(from: U, cp1: U, cp2: U, to: U, resolution: u32) -> Vec
where T: BaseFloat,
U: FloatVector + Copy {
let _3:T = num::traits::cast(3.0).unwrap();
let c:U = (cp1 - from) * _3;
let b:U = (cp2 - cp1) * _3 - c;
let a:U = to - from - c - b;
(0 .. resolution+1).map(|i|{
let t: T = num::traits::cast(i as f32 / resolution as f32).unwrap();
let t2 = t*t;
let t3 = t2*t;
a*t3 + b*t2 + c*t + from
}).collect()
}
fn main() {
bezier(Vector2::new(0f32, 0.),
Vector2::new(10., 10.),
Vector2::new(20., -10.),
Vector2::new(30., 0.),
20);
}
```
where a function takes a vector of any dimension U and it's type T and internally casts some real numbers to T and does some basic operations with the vector type and the numbers.
in 0.11 that becomes something like:
```rust
extern crate nalgebra;
extern crate alga;
extern crate num;
use nalgebra::*;
use std::ops::{Add,Sub,Mul};
pub fn bezier(from: ColumnVector,
cp1: ColumnVector,
cp2: ColumnVector,
to: ColumnVector,
resolution: u32) -> Vec>
where T: alga::general::Real + num::NumCast,
D: DimName,
ColumnVector: Add> +
Sub> +
Mul> +
Copy{
let _3:T = num::traits::cast(3.0).unwrap();
let c = (cp1 - from) * _3;
let b = (cp2 - cp1) * _3 - c;
let a = to - from - c - b;
(0 .. resolution+1).map(|i|{
let t: T = num::traits::cast(i as f32 / resolution as f32).unwrap();
let t2 = t*t;
let t3 = t2*t;
a*t3 + b*t2 + c*t + from
}).collect()
}
fn main() {
let b = bezier(Vector2::new(0f32, 0.), Vector2::new(10., 10.), Vector2::new(20., -10.), Vector2::new(30., 0.), 20);
}
```
which is already way more complex than before, needing to specify every operation used over the vector, again i'm not sure if there's any new class that does something similar to FloatVector but is suspect there's not since the storage type makes it harder to generalize every possible vector.
i also guess that using the num crate for number casting shouldn't be needed anymore with alga? but can't find anything to substitute it, have tried with supersetOf but can't get it to work.
now if i try to add a line of code where i get a zero vector things get even more complicated:
```
pub fn bezier(from: ColumnVector, cp1: ColumnVector, cp2: ColumnVector, to: ColumnVector, resolution: u32) -> Vec>
where T: alga::general::Real + num::NumCast,
D: DimName,
ColumnVector: Add> +
Sub> +
Mul> +
Copy {
let v: ColumnVector = zero();
...
```
now i get:
```
error[E0277]: the trait bound `S: nalgebra::storage::OwnedStorage` is not satisfied
--> src/main.rs:55:34
|
55 | let v: ColumnVector = zero();
| ^^^^ the trait `nalgebra::storage::OwnedStorage` is not implemented for `S`
|
= help: consider adding a `where S: nalgebra::storage::OwnedStorage` bound
= note: required because of the requirements on the impl of `alga::general::Identity` for `nalgebra::Matrix`
= note: required by `nalgebra::zero`
error[E0277]: the trait bound `S: nalgebra::storage::Storage` is not satisfied
--> src/main.rs:55:34
|
55 | let v: ColumnVector = zero();
| ^^^^ the trait `nalgebra::storage::Storage` is not implemented for `S`
|
= help: consider adding a `where S: nalgebra::storage::Storage` bound
= note: required because of the requirements on the impl of `alga::general::Identity` for `nalgebra::Matrix`
= note: required by `nalgebra::zero`
error: aborting due to 2 previous errors
```
if i add to the where clause of the function `S: storage::Storage` then i get:
```
error[E0271]: type mismatch resolving `<>::Alloc as nalgebra::allocator::Allocator>::Buffer == S`
--> src/main.rs:50:1
|
50 | pub fn bezier_zero(from: ColumnVector, cp1: ColumnVector, cp2: ColumnVector, to: ColumnVector, resolution: u32) -> Vec>
| _^ starting here...
51 | | where T: alga::general::Real + num::NumCast,
52 | | D: DimName,
53 | | S: storage::OwnedStorage,
54 | | ColumnVector: Add> + Sub> + Mul> + Copy{
55 | |
56 | | let v: ColumnVector = zero();
57 | | vec![v]
58 | | }
| |_^ ...ending here: expected associated type, found type parameter
|
= note: expected type `<>::Alloc as nalgebra::allocator::Allocator>::Buffer`
= note: found type `S`
= note: required by `nalgebra::storage::OwnedStorage`
error: aborting due to previous error
```
which doesn't give a clear hint of a possible solution anymore.
the real solution is not to add an storage type but instead add `alga::general::Identity` to the ColumnVector where clause
I've found similar problems while trying to port some code to 0.11 where adding some trait to solve some error triggers another to a point where the signature of every function becomes extra long and it's really hard to figure out but even once you figure it out then calling two functions from a thrid becomes another problem cause the requirements of the two functions somehow clash.
Not sure if there's already something like that in alga or nalgebra but if would be useful to have something similar to the old FloatVector that allows to specify the most commonly used VectorN without having to worry about specifying all the possible operations, storage type...
error messages have also become really cryptic because of the usage of Matrix for every type although i guess there's no solution for that unless the rust compiler optionally allowed to show aliases for types in errors instead of the original type
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.