\nWhat's the correct way to implement this ?
\nHere's my code :
pub trait VectorAbstract<TValue: Scalar>: VectorSpaceElement + // a dozen std traits\n{\n fn dot(lhs: &Self, rhs: &Self) -> TValue;\n}\n\npub trait VectorDynamic<TValue: Scalar>: VectorAbstract<TValue> {\n fn dim_count(&self) -> usize;\n fn from_list(arr: Vec<TValue>) -> Self;\n}\n\npub trait VectorStatic<TValue: Scalar, const DIM_COUNT: usize>: VectorAbstract<TValue> {\n fn from_array(arr: [TValue; DIM_COUNT]) -> Self;\n}\n\nimpl<TValue: Scalar, TVector: VectorDynamic<TValue>> VectorAbstract<TValue> for TVector {\n fn dot(lhs: &Self, rhs: &Self) -> TValue {\n // ... dot product body for dynamic vectors ...\n }\n}\n\nimpl<TValue: Scalar, const DIM_COUNT: usize, TVector: VectorStatic<TValue, DIM_COUNT>>\n VectorAbstract<TValue> for TVector\n{\n fn dot(lhs: &Self, rhs: &Self) -> TValue {\n // ... dot product body for static vectors ...\n }\n}\n
\nUPDATE 1
\nI also tried the following :
\npub trait VectorStatic<TValue: Scalar>: VectorAbstract<TValue> {\n const DIM_COUNT: usize;\n fn from_array(arr: [TValue; Self::DIM_COUNT]) -> Self;\n}\nimpl<TValue: Scalar, TVector: VectorStatic<TValue>> VectorAbstract<TValue> for TVector {\n fn dot(lhs: &Self, rhs: &Self) -> TValue {\n // ... dot product body for static vectors ...\n }\n}\n
\nBut I get the following error where I'm declaring the from_array
function :
generic parameters may not be used in const operations \ncannot perform const operation using `Self` \nnote: type parameters may not be used in const expressions \n
\nNote : I want the DIM_COUNT to be obtained in compile time somehow, so no fn dim_count()
for VectorStatic
.
UPDATE 2
\nAlso when I completely remove the implementation for VectorStatic, I get another error in another file where I have a Vector2
struct and try to implement VectorStatic<TValue, 2>
for that:
pub struct Vector2<TValue: Scalar> {\n pub x: TValue,\n pub y: TValue,\n}\nimpl<TValue: Scalar> VectorStatic<TValue, 2> for Vector2<TValue> {\n // ... implementation ...\n}\n
\nAnd here's the error :
\nthe trait bound `math::algebra::vectors::vector2::Vector2<TValue>: math::algebra::abstractions::VectorDynamic<TValue>` is not satisfied\nthe trait `math::algebra::abstractions::VectorDynamic<TValue>` is not implemented for `math::algebra::vectors::vector2::Vector2<TValue>`\n
\nNote that this Vector2 struct is not supposed to be a VectorDynamic
at all.\nThere's definitely something I have not understood clearly here, maybe rust thinks I'm trying to make every VectorAbstract
a VectorDynamic
or something like that ?
\nWhat is it that I'm missing ?
UPDATE 3
\nPerhaps I should also mention that I already tried the following :
\nimpl<TValue: Scalar> VectorAbstract<TValue> for dyn VectorDynamic<TValue>\n{\n fn dot(lhs: &Self, rhs: &Self) -> TValue {\n // ... dot product body for dynamic vectors ...\n }\n}\nimpl<TValue: Scalar, const DIM_COUNT: usize> VectorAbstract<TValue> for dyn VectorStatic<TValue, DIM_COUNT>\n{\n fn dot(lhs: &Self, rhs: &Self) -> TValue {\n // ... dot product body for static vectors ...\n }\n}\n
\nBut in that case I get this error for both :
\nthe trait `math::algebra::abstractions::VectorDynamic/VectorStatic` cannot be made into an object\n
\nand then a dozen lines that say because they used Self
as a type parameter.
The problem with your original code is that there are no guarantees that a type TVector
will only implement VectorStatic<TValue, 1>
and not implement VectorStatic<TValue, 2>
which would give conflicting implementations of VectorAbstract<TValue>
.
Update 1 is the way to go, since that way a type cannot implement VectorStatic
more than once. Currently this requires nightly rust with #![feature(generic_const_exprs)]
added at the start of lib.rs
/main.rs
The next problem will be the 2 impl
-s of VectorAbstract<TValue>
. Again there is nothing to guarantee that TVector
does not implement both VectorDynamic<TValue>
and VectorStatic<TValue>
which would give conflicting implementations of VectorAbstarct<TValue>
. As far as I know this cannot be done even with unstable features. The best way do it is to use wrapper structs.
VectorStatic1
+ VectorStaticWrapper1
requires the added feature and works only in nightly rust version, VectorStatic2
+ VectorStaticWrapper2
works in stable.
#![feature(generic_const_exprs)]\n\npub trait Scalar {}\n\npub trait VectorAbstract<TValue: Scalar>: \n{\n fn dot(lhs: &Self, rhs: &Self) -> TValue;\n}\n\npub trait VectorDynamic<TValue: Scalar>: VectorAbstract<TValue> {\n fn dim_count(&self) -> usize;\n fn from_list(arr: Vec<TValue>) -> Self;\n}\n\npub trait VectorStatic1<TValue: Scalar>: VectorAbstract<TValue> {\n const DIM_COUNT: usize;\n fn from_array(arr: [TValue; Self::DIM_COUNT]) -> Self;\n}\n\npub trait VectorStatic2<TValue: Scalar, const DIM_COUNT: usize>: VectorAbstract<TValue> {\n fn from_array(arr: [TValue; DIM_COUNT]) -> Self;\n}\n\nstruct VectorDynamicWrapper<T>(T);\nstruct VectorStaticWrapper1<T>(T);\nstruct VectorStaticWrapper2<T, const DIM_COUNT: usize>(T);\n\nimpl<TValue: Scalar, TVector: VectorDynamic<TValue>> VectorAbstract<TValue> for VectorDynamicWrapper<TVector> {\n fn dot(lhs: &Self, rhs: &Self) -> TValue {\n let lhs = &lhs.0;\n let rhs = &rhs.0;\n todo!()\n }\n}\n\nimpl<TValue: Scalar, TVector: VectorStatic1<TValue>>\n VectorAbstract<TValue> for VectorStaticWrapper1<TVector>\n{\n fn dot(lhs: &Self, rhs: &Self) -> TValue {\n let lhs = &lhs.0;\n let rhs = &rhs.0;\n let dim_count = TVector::DIM_COUNT;\n todo!()\n }\n}\n\nimpl<TValue: Scalar, const DIM_COUNT: usize, TVector: VectorStatic2<TValue, DIM_COUNT>>\n VectorAbstract<TValue> for VectorStaticWrapper2<TVector, DIM_COUNT>\n{\n fn dot(lhs: &Self, rhs: &Self) -> TValue {\n let lhs = &lhs.0;\n let rhs = &rhs.0;\n todo!()\n }\n}\n
\n","author":{"@type":"Person","name":"susitsm"},"upvoteCount":1}}}Reputation: 97
I'm trying to implement some abstract linear algebra traits and structs as part of my practices learning rust. In the code below when I implement VectorAbstract<TValue>
for VectorDynamic<TValue>
there's no problem; but when I try to do the same for VectorStatic<TValue, DIM_COUNT>
I get the following error :
the const parameter `DIM_COUNT` is not constrained by the impl trait, self type, or predicates
unconstrained const parameter
note: expressions using a const parameter must map each value to a distinct output value
note: proving the result of expressions other than the parameter are unique is not supported
What am I doing wrong here ?
What's the correct way to implement this ?
Here's my code :
pub trait VectorAbstract<TValue: Scalar>: VectorSpaceElement + // a dozen std traits
{
fn dot(lhs: &Self, rhs: &Self) -> TValue;
}
pub trait VectorDynamic<TValue: Scalar>: VectorAbstract<TValue> {
fn dim_count(&self) -> usize;
fn from_list(arr: Vec<TValue>) -> Self;
}
pub trait VectorStatic<TValue: Scalar, const DIM_COUNT: usize>: VectorAbstract<TValue> {
fn from_array(arr: [TValue; DIM_COUNT]) -> Self;
}
impl<TValue: Scalar, TVector: VectorDynamic<TValue>> VectorAbstract<TValue> for TVector {
fn dot(lhs: &Self, rhs: &Self) -> TValue {
// ... dot product body for dynamic vectors ...
}
}
impl<TValue: Scalar, const DIM_COUNT: usize, TVector: VectorStatic<TValue, DIM_COUNT>>
VectorAbstract<TValue> for TVector
{
fn dot(lhs: &Self, rhs: &Self) -> TValue {
// ... dot product body for static vectors ...
}
}
UPDATE 1
I also tried the following :
pub trait VectorStatic<TValue: Scalar>: VectorAbstract<TValue> {
const DIM_COUNT: usize;
fn from_array(arr: [TValue; Self::DIM_COUNT]) -> Self;
}
impl<TValue: Scalar, TVector: VectorStatic<TValue>> VectorAbstract<TValue> for TVector {
fn dot(lhs: &Self, rhs: &Self) -> TValue {
// ... dot product body for static vectors ...
}
}
But I get the following error where I'm declaring the from_array
function :
generic parameters may not be used in const operations
cannot perform const operation using `Self`
note: type parameters may not be used in const expressions
Note : I want the DIM_COUNT to be obtained in compile time somehow, so no fn dim_count()
for VectorStatic
.
UPDATE 2
Also when I completely remove the implementation for VectorStatic, I get another error in another file where I have a Vector2
struct and try to implement VectorStatic<TValue, 2>
for that:
pub struct Vector2<TValue: Scalar> {
pub x: TValue,
pub y: TValue,
}
impl<TValue: Scalar> VectorStatic<TValue, 2> for Vector2<TValue> {
// ... implementation ...
}
And here's the error :
the trait bound `math::algebra::vectors::vector2::Vector2<TValue>: math::algebra::abstractions::VectorDynamic<TValue>` is not satisfied
the trait `math::algebra::abstractions::VectorDynamic<TValue>` is not implemented for `math::algebra::vectors::vector2::Vector2<TValue>`
Note that this Vector2 struct is not supposed to be a VectorDynamic
at all.
There's definitely something I have not understood clearly here, maybe rust thinks I'm trying to make every VectorAbstract
a VectorDynamic
or something like that ?
What is it that I'm missing ?
UPDATE 3
Perhaps I should also mention that I already tried the following :
impl<TValue: Scalar> VectorAbstract<TValue> for dyn VectorDynamic<TValue>
{
fn dot(lhs: &Self, rhs: &Self) -> TValue {
// ... dot product body for dynamic vectors ...
}
}
impl<TValue: Scalar, const DIM_COUNT: usize> VectorAbstract<TValue> for dyn VectorStatic<TValue, DIM_COUNT>
{
fn dot(lhs: &Self, rhs: &Self) -> TValue {
// ... dot product body for static vectors ...
}
}
But in that case I get this error for both :
the trait `math::algebra::abstractions::VectorDynamic/VectorStatic` cannot be made into an object
and then a dozen lines that say because they used Self
as a type parameter.
Upvotes: 2
Views: 2085
Reputation: 485
The problem with your original code is that there are no guarantees that a type TVector
will only implement VectorStatic<TValue, 1>
and not implement VectorStatic<TValue, 2>
which would give conflicting implementations of VectorAbstract<TValue>
.
Update 1 is the way to go, since that way a type cannot implement VectorStatic
more than once. Currently this requires nightly rust with #![feature(generic_const_exprs)]
added at the start of lib.rs
/main.rs
The next problem will be the 2 impl
-s of VectorAbstract<TValue>
. Again there is nothing to guarantee that TVector
does not implement both VectorDynamic<TValue>
and VectorStatic<TValue>
which would give conflicting implementations of VectorAbstarct<TValue>
. As far as I know this cannot be done even with unstable features. The best way do it is to use wrapper structs.
VectorStatic1
+ VectorStaticWrapper1
requires the added feature and works only in nightly rust version, VectorStatic2
+ VectorStaticWrapper2
works in stable.
#![feature(generic_const_exprs)]
pub trait Scalar {}
pub trait VectorAbstract<TValue: Scalar>:
{
fn dot(lhs: &Self, rhs: &Self) -> TValue;
}
pub trait VectorDynamic<TValue: Scalar>: VectorAbstract<TValue> {
fn dim_count(&self) -> usize;
fn from_list(arr: Vec<TValue>) -> Self;
}
pub trait VectorStatic1<TValue: Scalar>: VectorAbstract<TValue> {
const DIM_COUNT: usize;
fn from_array(arr: [TValue; Self::DIM_COUNT]) -> Self;
}
pub trait VectorStatic2<TValue: Scalar, const DIM_COUNT: usize>: VectorAbstract<TValue> {
fn from_array(arr: [TValue; DIM_COUNT]) -> Self;
}
struct VectorDynamicWrapper<T>(T);
struct VectorStaticWrapper1<T>(T);
struct VectorStaticWrapper2<T, const DIM_COUNT: usize>(T);
impl<TValue: Scalar, TVector: VectorDynamic<TValue>> VectorAbstract<TValue> for VectorDynamicWrapper<TVector> {
fn dot(lhs: &Self, rhs: &Self) -> TValue {
let lhs = &lhs.0;
let rhs = &rhs.0;
todo!()
}
}
impl<TValue: Scalar, TVector: VectorStatic1<TValue>>
VectorAbstract<TValue> for VectorStaticWrapper1<TVector>
{
fn dot(lhs: &Self, rhs: &Self) -> TValue {
let lhs = &lhs.0;
let rhs = &rhs.0;
let dim_count = TVector::DIM_COUNT;
todo!()
}
}
impl<TValue: Scalar, const DIM_COUNT: usize, TVector: VectorStatic2<TValue, DIM_COUNT>>
VectorAbstract<TValue> for VectorStaticWrapper2<TVector, DIM_COUNT>
{
fn dot(lhs: &Self, rhs: &Self) -> TValue {
let lhs = &lhs.0;
let rhs = &rhs.0;
todo!()
}
}
Upvotes: 1