Skip to content

Tracking Issue for slice::array_chunks #74985

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

Open
6 tasks
lcnr opened this issue Jul 31, 2020 · 119 comments
Open
6 tasks

Tracking Issue for slice::array_chunks #74985

lcnr opened this issue Jul 31, 2020 · 119 comments
Labels
A-array Area: `[T; N]` A-const-generics Area: const generics (parameters and arguments) A-slice Area: `[T]` C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. F-generic_const_exprs `#![feature(generic_const_exprs)]` finished-final-comment-period The final comment period is finished for this PR / Issue. Libs-Tracked Libs issues that are tracked on the team's project board. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. to-announce Announce this issue on triage meeting

Comments

@lcnr
Copy link
Contributor

lcnr commented Jul 31, 2020

The feature gate for the issue is #![feature(array_chunks)].

Also tracks as_(r)chunks(_mut) in #![feature(slice_as_chunks)] -- these were FCPed starting at #74985 (comment) below.

About tracking issues

Tracking issues are used to record the overall progress of implementation.
They are also uses as hubs connecting to other relevant issues, e.g., bugs or open design questions.
A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature.
Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.

Steps

Unresolved Questions

Implementation history

@lcnr lcnr added C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC A-const-generics Area: const generics (parameters and arguments) F-const_generics `#![feature(const_generics)]` T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. labels Jul 31, 2020
@KodrAus KodrAus added Libs-Tracked Libs issues that are tracked on the team's project board. A-slice Area: `[T]` labels Aug 6, 2020
bors added a commit to rust-lang-ci/rust that referenced this issue Sep 12, 2020
Add `slice::array_chunks_mut`

This follows `array_chunks` from rust-lang#74373 with a mutable version, `array_chunks_mut`. The implementation is identical apart from mutability. The new tests are adaptations of the `chunks_exact_mut` tests, plus an inference test like the one for `array_chunks`.

I reused the unstable feature `array_chunks` and tracking issue rust-lang#74985, but I can separate that if desired.

r? `@withoutboats`
cc `@lcnr`
tmandry added a commit to tmandry/rust that referenced this issue Sep 16, 2020
Add array_windows fn

This mimicks the functionality added by array_chunks, and implements a const-generic form of
`windows`. It makes egregious use of `unsafe`, but by necessity because the array must be
re-interpreted as a slice of arrays, and unlike array_chunks this cannot be done by casting the
original array once, since each time the index is advanced it needs to move one element, not
`N`.

I'm planning on adding more tests, but this should be good enough as a premise for the functionality.
Notably: should there be more functions overwritten for the iterator implementation/in general?

~~I've marked the issue as rust-lang#74985 as there is no corresponding exact issue for `array_windows`, but it's based of off `array_chunks`.~~

Edit: See Issue rust-lang#75027 created by @lcnr for tracking issue

~~Do not merge until I add more tests, please.~~

r? @lcnr
JohnTitor added a commit to JohnTitor/rust that referenced this issue Oct 26, 2020
…lbertodt

Add [T]::as_chunks(_mut)

Allows getting the slices directly, rather than just through an iterator as in `array_chunks(_mut)`.  The constructors for those iterators are then written in terms of these methods, so the iterator constructors no longer have any `unsafe` of their own.

Unstable, of course. rust-lang#74985
@joshlf
Copy link
Contributor

joshlf commented Feb 10, 2021

Is there any intention of providing the reverse versions of these functions?

@thomcc
Copy link
Member

thomcc commented Apr 25, 2021

Is there any intention of providing the reverse versions of these functions?

What would that look like?

@joshlf
Copy link
Contributor

joshlf commented Apr 26, 2021

Same API, but iterating backwards. I have a use case in which I need to convert either a prefix or a suffix of a slice to an array reference. This API is perfect for the prefix use case, and I'd love to be able to use it for the suffix use case as well.

@newpavlov
Copy link
Contributor

@joshlf
Both slice of arrays and custom iterator type would implement the DoubleEndedIterator, so your use case does not need a separate reverse method.

@joshlf
Copy link
Contributor

joshlf commented Apr 26, 2021

That's only true if N evenly divides the length of the slice (see array_chunks docs). Otherwise, the remaining elements are only accessible via the remainder method, and won't be iterated over in the DoubleEndedIterator implementation.

@newpavlov
Copy link
Contributor

Ah, I misunderstood your use case, you want [0, 1, 2, 3, 4, 5, 6] to be split into [4, 5, 6], [1, 2, 3], [0], not into [6], [3, 4, 5], [0, 1, 2]. It indeed requires a separate method.

@joshlf
Copy link
Contributor

joshlf commented Apr 26, 2021

Yep, exactly 😃

@thomcc
Copy link
Member

thomcc commented Apr 27, 2021

Yeah, array_rchunks is definitely worth having.

@sffc
Copy link

sffc commented May 12, 2021

Also useful would be the inverse operation: [[0, 1, 2], [3, 4, 5]] to [0, 1, 2, 3, 4, 5]. (from &[[T; 3]] to &[T])

@ChayimFriedman2
Copy link
Contributor

Do we need to wait until const_evaluatable_unchecked is stabilized so we can deny N = 0 at compile time to stabilize this feature? Perhaps we can just mention in the documentation that currently it panics but it may be uplifted to a compile time error in the future.

@fzyzcjy
Copy link

fzyzcjy commented Oct 7, 2021

Hi, is there any alternatives before this is stable? Thanks!

@CryZe
Copy link
Contributor

CryZe commented Oct 7, 2021

Hi, is there any alternatives before this is stable? Thanks!

Yeah bytemuck::cast_slice and bytemuck::cast_slice_mut can do mostly the same (with a Pod requirement though)

@fzyzcjy
Copy link

fzyzcjy commented Oct 7, 2021

Thanks!

@BurntSushi
Copy link
Member

I'd like to note that #74985 (comment) for explaining why take the less conservative approach and which real-world code needs to check N wasn't addressed yet.

I personally didn't respond because to me, examples aren't what convinces me to prefer panics. Post-mono errors are what convinces me to prefer panics. (Because I think post-mono errors should be avoided at almost all costs.)

@scottmcm
Copy link
Member

scottmcm commented Apr 2, 2025

I guess my mind got these methods mixed up with split_first_chunk...

I'll just second this point, actually, because I think it's a good one. I used to write .as_chunks().0[0] in examples because there wasn't a .first_chunk().unwrap() so it was by far the easiest way to get an array. But thankfully we have better ways than that horrible snippit now 🙂

the length of the slice being the (mathematically undefined) dividend

A really interesting (but slightly off-topic) thing this makes me think about: Okasaki chapter 9 is about numerical representations, and the equivalence between a way of writing a number and a container of that length. The simplest example is that a linked list is a unary representation of its own length. The book does a neat job of extending that to other things too, like what the container equivalent of a binary number would be -- and how the push/concat implementation on the data structure ends up with the same complexity as the increment/addition operator on a binary number.

So from that perspective, &[T] is a number, and first_chunk is checked_sub on that number, as_chunks is /+% on that number, and as_flattened is *-by-a-constant on it.

@joboet
Copy link
Member

joboet commented Apr 2, 2025

A really interesting (but slightly off-topic) thing this makes me think about: Okasaki chapter 9 is about numerical representations, and the equivalence between a way of writing a number and a container of that length. The simplest example is that a linked list is a unary representation of its own length. The book does a neat job of extending that to other things too, like what the container equivalent of a binary number would be -- and how the push/concat implementation on the data structure ends up with the same complexity as the increment/addition operator on a binary number.

So from that perspective, &[T] is a number, and first_chunk is checked_sub on that number, as_chunks is /+% on that number, and as_flattened is *-by-a-constant on it.

This is getting very off-topic, but this equivalence is what I found so incredibly fascinating about lambda calculus. It's taught me that data is defined by how you interact with it – and these interactions are basically nothing but folds.

@Kixunil
Copy link
Contributor

Kixunil commented Apr 3, 2025

@BurntSushi thanks, just note that I've read somewhere that post-mono errors are preferred over panics. I'm not sure if the stance on this changed yet.

@shepmaster
Copy link
Member

I've read somewhere

Perhaps you mean this comment?

it had been asserted and then repeated in this thread that the lang team prefers runtime panics over post-mono errors. That's not the case. We like errors to happen as soon as possible. So we prefer pre-mono errors over post-mono errors when possible, but similarly we prefer post-mono errors over runtime errors when that is possible and practical

@Kixunil
Copy link
Contributor

Kixunil commented Apr 3, 2025

@shepmaster correct, thanks!

@Jules-Bertholet
Copy link
Contributor

Jules-Bertholet commented Apr 8, 2025

I personally didn't respond because to me, examples aren't what convinces me to prefer panics. Post-mono errors are what convinces me to prefer panics. (Because I think post-mono errors should be avoided at almost all costs.)

I would rather wait for the language features (e.g., pattern types) such that this check could become a proper pre-mono error. The standard library is forever. If we stabilize a sub-par API now, we will be stuck with it for as long as people keep using Rust. There is no reason to rush; people can always use an external crate if they need this feature now.

@Kixunil
Copy link
Contributor

Kixunil commented Apr 8, 2025

FTR, I thought that post-mono errors can be changed to pre-mono but they can't:

fn foo<const N: usize>(x: &[u8]) {
    bar(x.as_chunks::<N>());
}

foo::<42>(y);

Would become invalid if as_chunks suddenly started requiring foo to add where N != 0 bound.
So it'd be really great if it just forced people to pass in specific value.

@RalfJung
Copy link
Member

RalfJung commented Apr 8, 2025

So it'd be really great if it just forced people to pass in specific value.

That's probably possible for the compiler to enforce though it feels ad-hoc. Cc @BoxyUwU

It also feels like it'd be very annoying. I couldn't write functions as a user that wrap as_chunks and that are themselves generic. I don't think we should do that.

@lcnr
Copy link
Contributor Author

lcnr commented Apr 8, 2025

That's probably possible for the compiler to enforce though it feels ad-hoc.

Very much possible, yeah 😁

@hanna-kruppe
Copy link
Contributor

I would rather wait for the language features (e.g., pattern types) such that this check could become a proper pre-mono error. The standard library is forever. If we stabilize a sub-par API now, we will be stuck with it for as long as people keep using Rust. There is no reason to rush; people can always use an external crate if they need this feature now.

In practice what happens is not “people pull in some well-known crate that does it properly” (a quick search found one crate that provides it but it has exactly one dependent). Instead, they either contort their code to make do with stable standard library functions (example I wrote myself recently) that already exist, or they just implement it themselves with some unsafe (hopefully in a way that’s sound for N = 0). There is a small but nonzero amount of friction smeared across the Rust ecosystem due to the standard library not stabilizing this functionality. It’s not obvious to me that “the standard library is forever” outweighs that. The worst case outcome is that it either gets deprecated in a couple of years and a better way is added, or we’ll consider pre-mono errors better but not better enough to be worth the churn of deprecation. Either way, the cost is very small: it’s just a couple inherent methods that are marginally worse than they could’ve been in a perfect world, nothing with deep or far-reaching repercussions.

It’s not even obvious to me that there will be a clearly better way to have pre-mono errors in future Rust. There are vague ideas for what language features could enable them, but there’s no experience with how well they work in practice. So I don’t consider it a given that T-libs-api will say in five years “obviously the API should do XYZ to get a pre-mono error for N = 0”. Some way to put bounds on the values of const parameters will probably be needed eventually, but using it for preventing the specific error we’re talking about here may not be a good API design tradeoff after all.

@BoxyUwU
Copy link
Member

BoxyUwU commented Apr 8, 2025

@RalfJung yes I suggest something like that upthread but it seems like libs is not interested in deferring supporting generic callers until we know how things will pan out with enforcing the N>0 requirement in the type system. as you noted it would prevent being able to generically wrap array_chunks callsites which may or may not be desirable tradeoff depending on where you lean in terms of just shipping something useful now even though it might wind up being an unfortunate decisions 5 years down the raod

@its-the-shrimp
Copy link
Contributor

I agree with the sentiment to shrimply postpone this until there's a better way to enforce N != 0, this isn't an important trait, the absence of which creates discord in the ecosystem, it's just a couple utility methods, the current signature of which, shall it be stabilised now, will 100% be seen as an unfortunate, rushed decision a couple years down the road.

@its-the-shrimp
Copy link
Contributor

And I don't think we'll never get mechanisms for enforcing that at compile-time, e.g. changing N: usize to N: NonZeroUsize seems pretty much possible in the very near future, I wouldn't be pessimistic about this

@hanna-kruppe
Copy link
Contributor

hanna-kruppe commented Apr 8, 2025

Note that even if const N: NonZeroUsize becomes possible next year (Boxy’s estimate upthread), it’ll be very unergonomic to use in some cases. For example, since there’s no NonZero literals, you’ll need to write something like as_chunks::<{ NonZero::new(5).unwrap() }>() instead of just as_chunks::<5>(). Maybe hinting the length of the resulting arrays somewhere else could guide inference but I haven’t seen any discussion of how that would work. Similar problems apply to named constants that otherwise would be a plain usize. So without betting on further (speculative) language features that reduce these burdens, the const N: NonZeroUsize option isn’t obviously better.

@Sympatron
Copy link

If as_chunks would be stabilized with specific values only, it would be somewhat ad-hoc, but it would also be compatible with all other proposed solutions in the future without any breaking changes. And although it could not be used in all places where it might be useful, it could at least be used in many common cases and it could quite easily be stabilized in the near future.

This wouldn't be the first case where a subset of a feature is stabilized because it is useful enough on it's own (see const-generics).

@BurntSushi
Copy link
Member

I largely agree with @hanna-kruppe here with regards to postponing. Also, just more broadly speaking, the downside here is not significant from my perspective. We're not talking about a subtle footgun that could lead to incorrect answers. We're talking about a slightly worse failure mode for one particular corner case. That on its own isn't enough to delay a useful API like this indefinitely IMO.

@Jules-Bertholet
Copy link
Contributor

Jules-Bertholet commented Apr 8, 2025

In practice what happens is not “people pull in some well-known crate that does it properly” (a quick search found one crate that provides it but it has exactly one dependent). Instead, they either contort their code to make do with stable standard library functions (example I wrote myself recently) that already exist, or they just implement it themselves with some unsafe (hopefully in a way that’s sound for N = 0).

I agree that the present situation isn’t absolutely ideal. But I think the way to address it is something like Niko Matsakis’s “preview crates” idea, or the futures crate. Adding a dependency is far less of an issue if people know it’s blessed by the Rust team. And this feature would be a perfect test case!

@hanna-kruppe
Copy link
Contributor

In this particular case I don’t think that’ll really help. I’m not avoiding depending on a crate for this functionality because of trust, but because these functions are so trivial (ca. five lines of code each) that the complication and overhead of discovering a crate and depending on it is not worth it compared to the alternatives I described above.

A similar challenge applies on the Rust project side: who’s gonna be motivated to voluntarily take care of setting up a new repository and crate under the Rust project, publishing it, watch out for issues and PRs (unlikely in this specific case, but possible in theory), etc. when the code in question is so boring and the status quo is perfectly tolerable?

@BurntSushi
Copy link
Member

Yup. Same. I would never depend on a micro-crate providing a function like this, no matter who built it.

@rfcbot rfcbot added finished-final-comment-period The final comment period is finished for this PR / Issue. to-announce Announce this issue on triage meeting and removed final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. labels Apr 11, 2025
@rfcbot
Copy link
Collaborator

rfcbot commented Apr 11, 2025

The final comment period, with a disposition to merge, as per the review above, is now complete.

As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.

This will be merged soon.

ChrisDenton added a commit to ChrisDenton/rust that referenced this issue Apr 12, 2025
…lfJung

indirect-const-stabilize the `exact_div` intrinsic

See rust-lang#74985 (comment)
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Apr 13, 2025
Rollup merge of rust-lang#139163 - scottmcm:stabilize-exact_div, r=RalfJung

indirect-const-stabilize the `exact_div` intrinsic

See rust-lang#74985 (comment)
github-actions bot pushed a commit to model-checking/verify-rust-std that referenced this issue Apr 19, 2025
…lfJung

indirect-const-stabilize the `exact_div` intrinsic

See rust-lang#74985 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-array Area: `[T; N]` A-const-generics Area: const generics (parameters and arguments) A-slice Area: `[T]` C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. F-generic_const_exprs `#![feature(generic_const_exprs)]` finished-final-comment-period The final comment period is finished for this PR / Issue. Libs-Tracked Libs issues that are tracked on the team's project board. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. to-announce Announce this issue on triage meeting
Projects
None yet
Development

No branches or pull requests