Skip to content

Array length inference? #40269

Closed
Closed

Description

@SimonSapin

It would be nice if _ were allowed instead of an expression for the length in array types and array expressions, in cases where the length can be inferred based on context:

fn main() {
    let a: [u8; 4] = [0; _];
    let b: [u8; _] = a;
}

rustc 1.17.0-nightly (b1e3176 2017-03-03)

error: expected expression, found `_`
 --> a.rs:2:26
  |
2 |     let a: [u8; 4] = [0; _];
  |                          ^

error: expected expression, found `_`
 --> a.rs:3:17
  |
3 |     let b: [u8; _] = a;
  |                 ^

error: aborting due to 2 previous error

In comparison, the item type in array expressions and array types can be inferred today:

fn main() {
    let a: [u8; 4] = ["0".parse::<_>().unwrap(); 4];
    let b: [_; 4] = a;
}

Activity

  1. eddyb commented on Mar 5, 2017

    @eddyb
    Contributor

    This would have to be a part of rust-lang/rfcs#1931, you should leave a comment there perhaps.

    The reason is that whenever you have a generic parameter (lifetime / type / const), you need inference variables to instantiate, at least in the (slightly modified) HM typesystem we use.
    A simple example is that Vec::new is <Vec<_>>::new, and _ creates an unique type inference variable.
    Similarly, if Vec had a from_array method with a const parameter, Vec::from_array would require a const inference variable, at least internally in the compiler, and so would any trait impl.

    Now, we could just not provide a surface syntax for this, but I think reusing _ is probably fine.

  2. SimonSapin commented on Mar 5, 2017

    @SimonSapin
    ContributorAuthor

    When I wrote the above it didn’t feel like an entirely new language feature, just a "simple" extension of the existing inference mechanism. But I can imagine how from an compiler internals point of view it could require most of the plumbing for const parameters in types.

  3. durka commented on Mar 5, 2017

    @durka
    Contributor

    See counted-array :)

    counted_array!(let local_arr: [i32; _] = [4, 5, 6]);
  4. mqudsi commented on Aug 12, 2018

    @mqudsi
    Contributor

    This is definitely something that should be part of the language spec - definitely not somewhere macros shine.

    A particular pain point with rust arrays comes when adding a member to a previously declared array or when declaring an array without knowing in that moment how long it will be.

    For example:

    const ARRAY: [u8; 2] = [1, 2];

    Coming back to it later and adding 3 to the array requires changing two places. This is quite obvious in this example, but when dealing with arrays with many (complex) elements spanning multiple lines or even pages, remembering to go up and change the signature is challenging.

    Additionally, when sitting down to write code for the first time, it is often the case that you don't know until you finish writing it how many members your array will have. For example,

    const VALID_EXTENSIONS: [String, _] = [
        "ext1",
        "ext2",
        "ext3",
        // let's stop and think for a while. What other extensions could we include here?
        // oh yes!
        "ext4",
        "ext5",
    }

    Only having reached the end of the list does one know how many they'll have. Painful.

  5. eddyb commented on Aug 18, 2018

    @eddyb
    Contributor

    @mqudsi In the general case, const generics will have to include _ for values, at least internally in the implementation (so we could easily support the _ syntax as well).

    However, in your example, it's also like rust-lang/rfcs#2010, in that the type is inferred from the RHS.
    cc @Centril Maybe we can revisit that RFC? I think some of the concerns were overblown.

  6. fiso commented on Mar 6, 2019

    @fiso

    The use-case for this seems incredibly clear. Am I understanding you all correctly when I interpret the counter-point as being that the meaning of the _-symbol would become less clear and coherent across the language? If so then could the problem just be solved by using an alternative syntax?

    How about simply:

    const VALID_EXTENSIONS: [String] = [
        "ext1",
        "ext2",
        "ext3",
        "ext4",
        "ext5",
    }

    Or alternatively, introduce a new symbol that carries no problematic baggage and use that in place of _ for this kind of situation.

    Or am I just misunderstanding the objections?

  7. steveklabnik commented on Mar 7, 2019

    @steveklabnik
    Contributor

    Given that this pretty clearly requires an RFC, I'm going to give it a close.

  8. Centril commented on Mar 7, 2019

    @Centril
    Contributor
  9. added
    A-const-evalArea: Constant evaluation, covers all const contexts (static, const fn, ...)
    on Dec 1, 2024
  10. CalinZBaenen commented on May 26, 2026

    @CalinZBaenen

    This is definitely something that should be part of the language spec - definitely not somewhere macros shine.

    A particular pain point with rust arrays comes when adding a member to a previously declared array or when declaring an array without knowing in that moment how long it will be.

    For example:

    const ARRAY: [u8; 2] = [1, 2];

    Coming back to it later and adding 3 to the array requires changing two places. This is quite obvious in this example, but when dealing with arrays with many (complex) elements spanning multiple lines or even pages, remembering to go up and change the signature is challenging.

    Additionally, when sitting down to write code for the first time, it is often the case that you don't know until you finish writing it how many members your array will have. For example,

    const VALID_EXTENSIONS: [String, _] = [
        "ext1",
        "ext2",
        "ext3",
        // let's stop and think for a while. What other extensions could we include here?
        // oh yes!
        "ext4",
        "ext5",
    }

    Only having reached the end of the list does one know how many they'll have. Painful.

    For me, it's not even about obviousness. I have started to pick up development on my game again, and I was modifying an associated constant, PlayerSkin::MENU_INFO, which had type [X; 13], but since the number ov skins changed, I also had to change the number in the array definition.

    I know it doesn't seem like a big deal in my case; however, it's just slightly obnoxious that I have to go out ov my way to change something other than the array contents for something that could, reasonably, be inferred at compile-time, given that my array is constant.

    impl PlayerSkin {
    	// ...
    	
    	pub(crate) const MENU_INFO:[(Self, usize); 11] = [
    		(Self::Red, 0), (Self::Blue, 0), (Self::Green, 0), (Self::Brown, 0),
    		(Self::Black, 0), (Self::White, 0), (Self::BW, 0), (Self::Lilac, 0),
    		(Self::GB, 0), (Self::Bird, 10), (Self::Rainbow, 100)
    	];
    	
    	// ...
    }

    It would be nice if I could just replace the 11 with an underscore (_) or something and never have to worry about it again.

  11. eddyb commented on May 26, 2026

    @eddyb
    Contributor

    For the record, since this issue was closed, this now works:

    fn main() {
        let _: [u8; _] = [1, 2, 3];
    }

    The problem with the const case is that no part of the type of a const may be inferred¹ from the value.

    A macro can work around this by duplicating your array expression:

    macro_rules! const_array {
        (const $name:ident: [$elem:ty; _] = $array:expr;) => {
            const $name: [$elem; $array.len()] = $array;
        };
    }
    const_array! {
        const FOO: [u8; _] = [1, 2, 3];
    }

    EDIT:
    ¹ most recent discussion I can find on inferring the type of const/static is rust-lang/rfcs#3546 (comment) (sounded promising, but that was a year ago)

  12. Scripter17 commented on May 26, 2026

    @Scripter17
  13. scottmcm commented on Jun 2, 2026

    @scottmcm
    Member

    most recent discussion I can find

    FWIW, I remain more interested in other approaches than in just making it allowed. See things like rust-lang/rfcs#2545 (comment) for a pie in the sky wish. (Speaking as me, not as lang as a team.)

    Or, alternatively, I wonder if -- for places where people don't want to commit to a specific length -- we should just allow

    pub const VALID_EXTENSIONS: [String] = [
        "txt",
        "rs"
        "md",
    ];

    or similar. After all, if the author doesn't want to commit to a length, let [a, b, c] = VALID_EXTENSIONS; being a fallible pattern sounds like a good thing.

  14. CalinZBaenen commented on Jun 18, 2026

    @CalinZBaenen

    For the record, since this issue was closed, this now works:

    fn main() {
        let _: [u8; _] = [1, 2, 3];
    }

    The problem with the const case is that no part of the type of a const may be inferred¹ from the value.

    A macro can work around this by duplicating your array expression:

    macro_rules! const_array {
        (const $name:ident: [$elem:ty; _] = $array:expr;) => {
            const $name: [$elem; $array.len()] = $array;
        };
    }
    const_array! {
        const FOO: [u8; _] = [1, 2, 3];
    }

    EDIT: ¹ most recent discussion I can find on inferring the type of const/static is rust-lang/rfcs#3546 (comment) (sounded promising, but that was a year ago)

    Sorry for the late response, @eddyb. I have been unable to reply here because another GitHub user – whether or not through legitimate, authorized means – restricted my access to the rust-lang organization for reasons which can not be disclosed under the Rust language organizations Code of Conduct.

    I don't see why arrays can't be an exception to the const-type inference rule, since I would imagine the length is something the compiler could easily figure out.  (At least for array literals. Though, outside ov array literals, I do not know how else one would create a const array value.)

    After looking at the linked RFC, it seems tangentially related; though, it's more focused on types themselves, rather than const generics (i.e. length ov arrays) – and, in fact, one example shown in that RFC uses [_; 4].

    Also, as a previous comment stated, I feel like using macros to solve this is not an elegant solution; this feels like something the language should have an innate method ov solving.

  15. CalinZBaenen commented on Jun 18, 2026

    @CalinZBaenen

    FWIW, I remain more interested in other approaches than in just making it allowed. See things like rust-lang/rfcs#2545 (comment) for a pie in the sky wish. (Speaking as me, not as lang as a team.)

    Or, alternatively, I wonder if -- for places where people don't want to commit to a specific length -- we should just allow

    pub const VALID_EXTENSIONS: [String] = [
        "txt",
        "rs"
        "md",
    ];

    or similar. After all, if the author doesn't want to commit to a length, let [a, b, c] = VALID_EXTENSIONS; being a fallible pattern sounds like a good thing.

    I feel like after the type there should be a _, or there should at least be something after the type – even after seeing your other comment – because it could confuse both the person reading the type, as well as the Rust compiler, into thinking that someone is trying to declare a slice ov Strings.

    (Though, I'm sure you already thought ov that, as, in your other comment, you suggested a slightly different syntax: [T; numeric_type].)

  16. theemathas commented on Jun 19, 2026

    @theemathas
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-const-evalArea: Constant evaluation, covers all const contexts (static, const fn, ...)A-inferenceArea: Type inferenceC-feature-requestCategory: A feature request, i.e: not implemented / a PR.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions