Skip to content
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

Minimal const-generic bounds #56

Open
clarfonthey opened this issue Sep 8, 2024 · 0 comments
Open

Minimal const-generic bounds #56

clarfonthey opened this issue Sep 8, 2024 · 0 comments
Labels
C-design-docs Category: This is part of our design documentation

Comments

@clarfonthey
Copy link

What is this

This is a design document for const generics. Any discussions about its content should be on zulip. The conclusions of these discussions should then be edited back into this issue. Please do not post any comments directly in this issue.

(FWIW: I don't like this policy, but will abide by it.)

Content

This was on my mind for a couple of reasons, namely the generic integers v2 RFC and the lack of Default for arrays of arbitrary size, among other things.

Although it hasn't been entirely solidified with regard to const generics (see: #29, rust-lang/rust#95174 (comment)), it seems that the general consensus regarding structural equality has been settled: pattern-matching is the canonical way that equality works for constants.

A lot of existing proposals recommend expressions for constant bounds, which always felt far out of reach, and in particular requires generic_const_exprs. But patterns seem pretty easy to reconcile:

impl<T> Default for [T; 0] {
    fn default() -> [T; 0] { [] }
}
impl<T, const N: usize> Default for [T; N]
where
    N in 1..,
{
    fn default() -> [T; N] {
        let mut x = [const { MaybeUninit::uninit() }; N];
        let mut idx = 0;
        while idx < N {
            x[idx].write(T::default());
            idx += 1;
        }
        x.map(MaybeUninit::assume_init)
    }
}

Note that the CONST in PAT syntax here is entirely replaceable with something else; I just chose something that would be usable for an initial implementation, and in is one of the few keywords I figured would work. I don't like using anything that looks like an expression, since N = 1.. would visually look like setting the value equal to the RangeFrom expression, not matching a pattern.

The idea here is that we already have the mechanisms to check for exhaustiveness with regards to constants and patterns, and so we could just reuse this machinery for const generics. Additionally, it means that any usages of these impls would have to add these patterns to the bounds unless they were completely exhaustive, i.e., something like this:

impl<const N: usize> MyTrait for [T; N] where N in 1..=2 {}
impl<const N: usize> MyTrait for [T; N] where N in 10..=20 {}
// ...

any equivalent bounds would be required to add the relevant where bounds of the form N in 1..=2 | 10..=20 /* | ... */, or stricter.

I hadn't seen this design proposed before, and decided it would be worth writing up. Technically, it could also be used to implement multiple const-generic impls at once, if you did something like:

impl<const N: usize> MyTrait for [T; N] where N in 8 | 16 | 32 | 64 | 128 {}

And I suppose that would be fine. We could probably find a way to detect anything of the form:

impl<const N: usize> MyTrait for [T; N] where N in CONST {}

And suggest replacing it with impl MyTrait for [T; CONST] {}. (Barring all the rules for generic_const_exprs also apply.)

@clarfonthey clarfonthey added the C-design-docs Category: This is part of our design documentation label Sep 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-design-docs Category: This is part of our design documentation
Projects
None yet
Development

No branches or pull requests

1 participant