-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
RFC: Elide array size #2545
RFC: Elide array size #2545
Conversation
I'm not opposed to value inference of this kind - in fact it excites me a lot. |
I can see that there is interest in having more daring inference here. However, as I've pointed out, this can lead to errors from a distance, if one static contains a const down the line whose type changes. Those errors could be hard to track down. At the very least, they'd be surprising. However, we may be able to tweak the error reporting in such a way that such errors are quickly resolved, and that'd be awesome. For now, similar to the const lifetimes RFC I wrote, let's take a smaller step and elide the length only where it is obvious from the same line of code. This will already give us very real ergonomic wins with very little cost both in readability and teachability (It just occurred to me that I should add a paragraph about error messages), and it doesn't preclude us from aiming for stronger inference later. |
text/0000-elide-array-size.md
Outdated
For example, you might write: | ||
|
||
```rust | ||
const CONST_CHARS: [u8; _] = b"This is really a byte array"; |
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.
Nit: the expression here needs to be *b"…"
(with a star added) because the type of byte string literals is &'static [u8; N]
. (Maybe it should have been plain [u8; N]
but oh well.)
So with this RFC as-is, the following would be an error, right? fn foo() -> [u8; 9] { /* details elided */ }
fn main() {
let bar: [u8; _] = foo();
} If so, this feels even more ad-hoc, non-uniform, and makes me wary of the teachability aspect.
I am specifically concerned with taking small steps; I wouldn't want to stabilize this, leave the language in an inconsistent state in the interim and do the difficult extensions possibly later. I want to be sure that the extensions both can and will happen. In particular, I expect that the following should work: struct Matrix<T, const N: usize, const M: usize> {
data: [[T; N]; M]
}
fn main() {
let foo: Matrix<u8, _, _> = Matrix { data: [[1, 2, 3], [4, 5, 6]] };
} |
That's an interesting case. As for your first example, As such I worry, that your proposal could lead to errors that are extremely hard to track down. So unless you can show me an algorithm to produce error messages for that case that makes those errors easy to fix, I remain unconvinced. I don't agree with your teachability argument either. If the size is trivially inferrable from the initializer, wildcards are allowed. Otherwise insert the size. |
This is no different from using // crate A:
pub fn producer() -> [u8; 9] { /* details elided */ }
// crate B:
pub fn consumer(arr: [u8; 9]) { /* details elided */ }
// crate C:
fn main() {
let bar = producer(); // No type annotations.
consumer(bar);
} Thus, by writing
cc @varkor As far as I know, most dependently typed languages can do this sort of in-function inference (or the languages would be intolerable to write in) and so it should not be novel in any way.
It is the "otherwise insert the size" that is surprising, compared to how inference currently works for types coupled with the fact that you are allowed to write |
To continue with my tradition of macro implementations of RFCs (except in this case I wrote the macro two years ago)... https://crates.io/crates/counted-array Clearly, I think this is a good idea. :) |
👍 I like the idea of handling the simple case people constantly run into first. I've wanted this many times. |
One of the most annoying thing from using static arrays in rust is that there is no size inference, and you end up having to give the proper size. Which makes updates to the arrays cumbersome. I was reading "This Week in Rust 252", which linked to (RFC: Elide array size)[rust-lang/rfcs#2545], set to address this very problem, and @durka linked to his counted-arrays crate, which already existed and essentially implements the idea behind the RFC.
I like this RFC a lot. Having to maintain the array length manually is boilerplate causing unnecessary work -- counting things is something computers are good at -- I know this would have samed me some edit-compile cycles. |
@Centril I am sympathetic to your interest in uniformity and wouldn't be against inference for partial type ascription in I'm still defending the principle of locality for |
I would like to have this. For the concerns @Centril have, I propose the following rule:
so fn foo() -> [u8; 9] { /* details elided */ }
fn main() {
let bar: [u8; _] = foo();
} is not legal as We need the rule for |
I don't believe this RFC is necessary - it is subsumed by const generics, perhaps other than the surface syntax. The ability to infer constants in types is essential to const generics, particularly when used in rust-lang/rust#53645 has already been open for just over a month now, and it already contains the needed implementation work (minus the surface syntax of Nominating for @rust-lang/lang meeting, with a preference to close. |
To be clear, my comment above is about inference wherever we accept inference today. For the types of Note that said decision interacts with this RFC two-fold:
That former shows why this is not as pressing of a problem, while the latter talks about pretty much the same strategy taken by this RFC. OTOH, the original RFC stands some chance of being revived, with perhaps some restrictions around integer fallback, and ignoring "the closure problem" (#2010 (comment)). |
Based on discussion in @rust-lang/lang, we agreed that (based on @eddyb's comments above) const generics addresses the implementation of this, so the RFC as written is not quite what we're looking for. However, we do think that there's an RFC needed to explicitly allow inferring the const values in the types of const values, in specified circumstances, including array sizes. @llogiq, would you be open to restructuring this RFC into that, and referencing the const generics work as how this will be implemented? |
I think perhaps the problem you are getting at @llogiq with local reasoning is in particular with inference for items defined elsewhere. A more precise mechanism to get at that problem could be to require explicit type ascription for const values (and perhaps types) that arise from |
@joshtriplett will do. I'll just have to understand #2000 and #2010 first 😄 |
text/0000-elide-array-size.md
Outdated
[drawbacks]: #drawbacks | ||
|
||
There is a modicum of complexity to extend the parser and AST which needs to be | ||
done for every Rust parser in existenct. However, the feature is minor, so the |
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.
existenct -> existence
text/0000-elide-array-size.md
Outdated
[summary]: #summary | ||
|
||
In arrays, allow to elide the size in the type and put an underscore there | ||
instead if it can be deduced from the initializer. For example: `static |
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 think the summary should already mention that we only want this inference if the length can be trivially obtained by either counting the elements of the array initializer or taking it verbatim from a repeat expression.
text/0000-elide-array-size.md
Outdated
needs to count the elements of an array manually to determine its size. Letting | ||
the compiler find the size reduces the potential for error. It also allows us | ||
to ascribe the array component type without requiring the size (which is – | ||
perhaps surprisingly – not currently allowed). |
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 have seen many situations where users just gave up and used const X: &[u8] = &[4, 5, 6];
in order to not need to specify the length.
One of the most annoying thing from using static arrays in rust is that there is no size inference, and you end up having to give the proper size. Which makes updates to the arrays cumbersome. I was reading "This Week in Rust 252", which linked to (RFC: Elide array size)[rust-lang/rfcs#2545], set to address this very problem, and @durka linked to his counted-arrays crate, which already existed and essentially implements the idea behind the RFC.
It's worth noting that after rust-lang/rust#64698, the compiler now has parser recovery for the common case of
|
I read the diff when it was made (I'm watching the RFC repo) and I don't think the concerns were resolved. The RFC talks about What I would like to see instead is that the grammar of expressions is amended with Moreover, I think the RFC should explain why, when we other wise do not allow global type inference, it is OK to have global type inference in this case. (That is, @cramertj's comment in #2545 (comment) should be addressed.) Finally, given that #2545 (comment) is now implemented it would be good to explain why that isn't enough and why a similar diagnostics-only thing for expressions wouldn't be enough. |
This might deserve its own RFC. |
@gnzlbg Possibly. I don't care strongly whether this RFC morphs into that or if a new one is made, but I am against ad-hoc additions in any case. |
@rfcbot resolved state-contextual-constraints-up-front |
@rfcbot fcp cancel So this FCP is ancient. I'm canceling it, along with some other ancient FCPs. That said, I suppose that the "core conflict" remains: do we want to try and do a targeted fix or fix this via a more general mechanism building on const generics? In today's meeting we discussed the idea of creating a proposal based on the general motivation of permitting things like In any case, as I said, I'm going to cancel the FCP and we can decide whether to move forward based on whether (a) we have people motivated in helping to push this proposal through to completion (including impl) and (b) we feel we have a willing liaison and enough bandwidth on lang-team to see that through. |
@nikomatsakis proposal cancelled. |
An observation here: this feels like the value-space version of what To flesh that out:
(Note that I'm only talking about |
@scottmcm now, just mash that up a bit with const generics somehow... fn example() -> impl [i32; const N: usize] {
[42]
} I wonder how it would work/look for non-array types. |
Since this was previously discussed, min_const_generics is now on the path to stabilization. Given that, and the amount of time that has passed since this proposal, we think this likely needs to be revisited as a project proposal. That project proposal would need to look at the impact of @rfcbot postpone |
Team member @joshtriplett has proposed to postpone this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
For my part, I'm still interested in seeing this happen. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
The final comment period, with a disposition to postpone, 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. The RFC is now postponed. |
This is a small-ish RFC for array size elision wherever it can be taken directly from the initializer. It is deliberately restricted like this to uphold locality and avoid errors at a distance.
Rendered