Blanket impl of SimdPartialOrd prevents any Wrapper<T> of T: SimdValue defining vectorised field impls
- Dominant language
- Rust
- Stars
- 347
- Forks
- 39
- PR merge metrics
- No merged PRs in 30d
Description
SimdPartialOrd is blanket implemented for _any_ `T: SimdValue + PartialOrd`.
I am working on the [`num_dual`](https://lib.rs/num_dual) crate, trying to make its dual number algebra work like a scalar does for nalgebra purposes. Here's a simplified [illustration of the problem (playground)](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d645ed1dec2bd7a6d78420b476a00479).
The illustration has a `DualNumber` type, which I would like to eventually support `DualNumber` etc. The object is to put one of those inside a nalgebra vector, i.e. `Vector3>`, and have *that* type produce vectorized code. So `DualNumber>` has to implement everything that f32 does. Including SimdRealField/SimdComplexField.
All of the SimdRealField/SimdComplexField traits require SimdPartialOrd. There is a blanket implementation of SimdPartialOrd, and the existence of that blanket impl prevents any type like `DualNumber` implementing SimdPartialOrd manually and generic over T's SimdValue implementation / choice of SimdBool.
A type like this needs to have `type SimdBool = T::SimdBool;` in its SimdValue, and then use the vectorised SimdBool in its implementations of SimdRealField/SimdComplexField. Since I can't implement SimdPartialOrd and am forced to rely on the blanket impl, I can't really generate those vectorised bools. And moreover, since I cannot implement SimdPartialOrd, I have to constrain the SimdRealField/SimdComplexField implementations to `T: SimdValue`, which means I cannot ever use those traits on `DualNumber`.
Essentially, the blanket implementation on SimdPartialOrd has foreclosed the possibility of vectorising any new algebraic field implementations in such a way that nalgebra can use them. The resulting DualNumber can only be used with f32 and f64 directly. It only has the un-vectorised code in RealField and ComplexField.
There is one workaround, which is unacceptable: do not implement PartialOrd on DualNumber. Then the trait solver will reject that blanket impl and you can make your own. But the whole point of this exercise was to have operator overloading work with nalgebra, I'm not giving up PartialOrd.
My recommendation is to add a marker trait like the one in the illustration, reproduced here:
```rust
trait OptIn {}
impl OptIn for f32 {}
impl OptIn for f64 {}
impl SimdPartialOrd for T
where
T: SimdValue + PartialOrd,
// and crucially, add this as a constraint
T: OptIn,
{}
```
That way, because `DualNumber` chooses not to implement `OptIn`, it is unaffected by the blanket impl of SimdPartialOrd. It can then
- `impl SimdValue for DualNumber where T: SimdValue` with `Element = DualNumber` and `SimdBool = T::SimdBool>`
- `impl SimdPartialOrd for DualNumber where T: SimdPartialOrd`, very simple forwarding impl (to only compare the real parts)
- `impl SimdRealField for DualNumber where T: SimdRealField`, using T's simd operations to implement dual numbers
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.