Constraints on `RStride` in generic code
- Dominant language
- Rust
- Stars
- 4.8k
- Forks
- 565
- PR merge metrics
- No merged PRs in 30d
Description
I'm using generic-heavy `nalgebra` code throughout my code base. This has worked well for the most part (after figuring out ways to reduce trait bounds verbosity by grouping functionality in traits with blanket impls). However, I've run into a problem which doesn't seem possible to solve in the same way. I'm posting it here in the hopes that someone might have an idea how to get around it.
As an example, consider the problem of taking a fully dynamic slice (i.e. dynamic rows, cols and strides) from a `MatrixMN` with generic dimensions [(playground)](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=25aeab0e1c113bfc3100498e88eb8258):
```rust
use nalgebra::{
DefaultAllocator, DimName, Dynamic, MatrixMN,
MatrixSlice, Scalar, U1};
use nalgebra::allocator::Allocator;
use nalgebra::storage::Storage;
fn take_slice(x: &MatrixMN)
where
T: Scalar,
R: DimName,
C: DimName,
DefaultAllocator: Allocator,
// With this bound, it would work. But this is not acceptible as we might
// need *many* such bounds when we have more dimensions than just T and R,
// which would be unacceptable when used in a public API, and
// I can't think of a way to use the "compound trait trick" to collect
// necessary trait bounds into a single trait on DefaultAllocator
>::Buffer: Storage
{
let _x_slice = MatrixSlice::::from(x);
}
```
With some kind of bound on the strides of the `Buffer` associated type of `Allocator`, we can not make it compile. This is a vastly simplified example compared to what I'm actually trying to do, but it is designed to show the root of the problem.
Now, as alluded to in the comments, in my real code, I have a compound trait containing a vast amount of constraints in the form of `Allocator + Allocator + Allocator + Allocator + ...` in order to allow me to work with different combinations of dimensions. Since there's no way (to my knowledge) of constructing a similar compound trait that constraints the *associated types* of `Allocator`, I can't find a way for me to impose the necessary constraints.
To summarize, it seems that, given a generic `MatrixMN`, I cannot take a slice of it unless either:
1. the slice type has the exact same `RStride` and `CStride` types (`Dynamic` isn't even possible here, since we don't have a `DimEq` bound, since we don't know that `RStride: DimName`)
2. we enforce trait bounds on `RStride`/`CStride`, but as shown above, this is very impractical, to the point of impossible in some cases (such as public APIs, in my case).
3. I use `.generic_slice_with_steps`, but that's only for the special case of fully `Dynamic` strides. I'd *much* prefer to constrain myself to unit `RStride` in order to avoid potential performance pitfalls. For my API, this would be totally reasonable, as non-unit strides are very exotic and not really useful for my particular use case.
Using option `3` does allow me to move on for the time being. I could also do a run-time assertion on unit-stride and convert it back into a unit-stride slice, although this is not so nice for API consumers. Are there any other options that would allow me to easily constrain slices in generic code?
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.