-
Notifications
You must be signed in to change notification settings - Fork 97
Use generic trait parameters to minimize associated types #493
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
base: master
Are you sure you want to change the base?
Conversation
| /// The mask type returned by each comparison. | ||
| type Mask; | ||
|
|
||
| pub trait SimdPartialEq<T, const N: usize> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
imo N should be an associated #[type_const] but last I knew that's not done being implemented yet.
something like:
pub trait SimdLen {
#[type_const]
const LEN: usize;
}
impl<T: SimdElement, const N: usize> SimdLen for Simd<T, N> {
#[type_const]
const LEN: usize = N;
}
impl<T: MaskElement, const N: usize> SimdLen for Mask<T, N> {
#[type_const]
const LEN: usize = N;
}
pub trait SimdBase: SimdLen {
type Element: SimdElement;
}
impl<T: SimdElement, const N: usize> SimdBase for Simd<T, N> {
type Element = T;
}
pub trait SimdPartialEq: SimdBase {
fn simd_eq(self, other: Self) -> Mask<<Self::Element as SimdElement>::Mask, { Self::LEN }>;
...
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that would allow your example function's bounds to just be:
fn foo<T: SimdElement>(x: Simd<T, 4>) -> Mask<T::Mask, 4>
where
// output types are completely deduced from the blanket
// SimdBase and SimdLen impls so no additional bounds are needed
Simd<T, 4>: SimdFloat,
{
x.is_sign_negative()
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sadly, it seems that hits the bug where specifying bounds hides information that could be deduced so the bound ends up having to be:
Simd<T, 4>: SimdFloat<Element = T, LEN = 4>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I got it to work with just Simd<T, 4>: SimdFloat by removing SimdFloat: SimdBase and instead having where Self: SimdBase on all items in the trait.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
further reduced feature gates: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=b57a420a75142e3eda48993dc2f981f1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we have to be bull-headed about getting something "incomplete" into core, then...?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, I'm a little conflicted because there do seem to be some ergonomics gains but I'd like to stick to features we can stabilize relatively soon so people can actually use the module
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think mGCA is quite ready for actual use yet so it'd still have to wait a bit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here's a messier workaround with no unstable features that has the exact same ergonomics as using #[type_const] for known length:
https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=02bdc66a7bf980b3b028474f47a2023f
basically there's an associated type that mostly acts like an associated #[type_const]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it also has just as nice ergonomics when the length is a const generic:
https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=29fba8f75be0e771bb5fd580e77f9c89
fn foo<T: SimdElement>(x: Simd<T, 4>) -> Mask<T::Mask, 4>
where
Simd<T, 4>: SimdFloat,
{
x.is_sign_negative()
}
fn bar<T: SimdElement, const N: usize>(x: Simd<T, N>) -> Mask<T::Mask, N>
where
Simd<T, N>: SimdFloat,
{
x.is_sign_negative()
}
This improves type inference by removing most associated types. For example, the following function doesn't actually work:
You actually need the constraint
Simd<T, 4>: SimdFloat<Mask = Mask<T::Mask, 4>>.With this PR, the function should look a little more like:
There are still a few instances that need associated types, but we can explore those individually to see if there's a better API.
Also, note that we now end up with a lot of instances of
Mask<<T as SimdElement>::Mask, N>. We can either remove theSimdElement::Maskassociated type with #483 or we can provide an alias to avoid writing that out.