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

Slice with size known at compile time should be coerced to array #1772

Open
est31 opened this Issue Oct 16, 2016 · 11 comments

Comments

Projects
None yet
7 participants
@est31
Copy link
Contributor

est31 commented Oct 16, 2016

You should be able to write stuff like:

fn do_sum(a: [u8; 2]) -> u8 {
    a[0] + a[1]
}

fn main() {
    let arr = [1, 2, 3, 4, 5, 6, 7, 8];
    println!("The sum is {}", do_sum(arr[0..2]));
}

If subslice notation ([] with a range inside) is used on a slice or array with the borders known at compile time, it should be coerced to an array.

There is a stackoverflow thread with a list of workarounds, and someone has even done a crate for the problem, but it should be solved inside the language, as it doesn't really feel natural.

Also, if one end is unspecified, it should allow for values only known at runtime for the specified end, and infer the unspecified end from the type of the function. Example code:

fn do_sum(a: [u8; 2]) -> u8 {
    a[0] + a[1]
}

fn main() {
    let arr = [1, 2, 3, 4, 5, 6, 7, 8];
    for i in 0 .. 8 {
        println!("The sum is {}", do_sum(arr[i..]));
    }
}

@nrc nrc added the T-lang label Oct 17, 2016

@oli-obk

This comment has been minimized.

Copy link
Contributor

oli-obk commented Oct 17, 2016

I've been thinking about a more general solution to this. &arr[0..2] should be &[T; 2]. If T is Copy then the semantics work like in your first suggestion. I'm not entirely sure if it's backwards compatible, but since &[T; N] coerces to &[T], it should work once generics allow coercions.

Also, if one end is unspecified, it should allow for values only known at runtime for the specified end, and infer the unspecified end from the type of the function.

That's a little surprising in my opinion.

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Oct 17, 2016

For &arr[0..2] to be &[T; 2], <[T; n] as Index<const i..j>>::Output has to be [T; j - i].
To be able to actually express that in the types, you'd have a feature which allows for much more powerful things, such as tuple indexing (e.g. (A, B) implementing Index<0usize> and Index<1usize>).

I call it "value refinement", that is, you've refined a type to a single value (any pattern can technically be a refinement and you can even have full subtyping with "pattern-refined types" if you wanted to).

But it's one of those typesystem extensions that are "less mainstream" than, say, HKT, or even GADTs.
I'm curious if someone knows how to do something like that in Haskell, if it's at all possible.

@est31

This comment has been minimized.

Copy link
Contributor Author

est31 commented Oct 17, 2016

@eddyb will the typesystem extensions of #1657 be enough?

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Oct 17, 2016

@est31 No, those are nowhere near allowing pair[0] and pair[1] to have different types (!!).

@burdges

This comment has been minimized.

Copy link

burdges commented Oct 18, 2016

I'm happy to learn about the arrayref crate because lacking this gets annoying.

@burdges

This comment has been minimized.

Copy link

burdges commented Oct 18, 2016

I think should go read about Index to better understand your comments here @eddyb .

@est31

This comment has been minimized.

Copy link
Contributor Author

est31 commented Oct 18, 2016

@burdges I've wondered about it as well and talked with @eddyb on IRC. In fact, not the Index trait is used here, but the Range struct. The problem is that the Range struct only has fields for the borders, whose value is only known at runtime. @eddyb is proposing that the issue is left until there is a generic way to work even with these values.

However, he confirmed that something like ConstRange would do the job as well be needed, where the borders are constant and fixed at compile time (as of #1657 merged). @eddyb didn't like that approach, due to the added complexity.

@burdges

This comment has been minimized.

Copy link

burdges commented Oct 18, 2016

I see. It's an issue of there being too many things like this, so they should be dealt with using something more general like #1657, as opposed to many little syntax hacks.

@VictorKoenders

This comment has been minimized.

Copy link

VictorKoenders commented Oct 13, 2018

I'd love to have this feature, especially with firmware development where compile-time checks like this are crucial

@SoniEx2

This comment has been minimized.

Copy link

SoniEx2 commented Oct 13, 2018

So uh, impl<T> From<&[T]> for Option<&[T; N]>?

@VictorKoenders

This comment has been minimized.

Copy link

VictorKoenders commented Oct 14, 2018

It's more like a specialization for indexing a slice by RangeInclusive and Range where const N: usize = range.end - range.end;

&slice[3..5] returns &[_; 2] but &slice[3..] would still return a &[_]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.