Add Runtime Construction Functions for [T;N] after Const Generics

Currently, if you want to create array for array types at runtime, the best practice is to create [MaybeUninit<T>; N] first and then initialize it by for loops, and finally use unsafe std::mem::transmute, according to docs of MaybeUninit<T>. Although this pattern is efficient and practical, it is not elegant and not easy to use, and it needs to use unsafe which maybe scares people.

Thus, I proposed to add a serial of construct functions for [T;N], after the shipping of the const generics. The proposed definition maybe:

impl<T, const usize N> for [T; N] {
  // create an array filled with any val that can be cloned
  fn new_with(val :T) -> [T; N] where T: Clone;
  
  // and more generally
  // create an array by a factory function returns T
  fn new_by(f: F) -> [T; N] where F: FnMut() -> T;
}  

Alternatives:

  1. The function names should be discussed to be more nature and elegant, because there is no similar constructors for containers before. Alternative names should be considered for better naming conversion.

  2. new_by function takes iterators, instead of functions.

    Or a bigger but more general change:

    add a TryFromIterator trait, just like TryFrom and From.

  3. Furthermore, these functions may be used in const context. This is helpful when generating a building-time look-up array for some algorithms. For this purpose, a construction function taking function with index is more useful, for example:

    // This function takes a function with index of current item, 
    //  so it can generate different items at different positions.
    const fn new_by_index(f: F) -> [T; N] where F: FnMut(usize) -> T;
    

    This function should be further discussed, because there is no similar function before.

  4. This initializer may benefit other containers, such as Vec. And it is more familiar for people who use c++ before, because std::vector can also be construct with N of T items.

Finally, I believe this change can improve array usability for everyone, however, more discussions may be required, and the detailed interface should be rechecked.

new_with is identical to the built-in array construction syntax [value; size].

Also, arrays impl TryFrom<Vec<T>> and array references impl TryFrom<&[T]>, so that should take care of the rest.

1 Like

Something like this would be nice, because new_by can also properly handle stack unwinding if there's a panic and correctly drop elements that have been constructed. I bet most user code that incrementally initializes [MaybeUninit<T>; N] will leak resources if there's a panic before the final transmute.

1 Like

But built-in array construction syntax [value; size], requires value to be const or impl Default, which is why we need to use [MaybeUninit<T>; N] in the first place.

1 Like

Besides, TryFrom<Vec<T>> maybe need to move/copy array data from heap to stack. This may be not as efficient as proposed methods.

In general, I'd be happy to have better support for creating arrays in the language/std (or, maybe core).

I'd just like to link this crate here: https://docs.rs/array-init/1.0.0/array_init/. It kind of does what you propose, so it would be nice to think about this proposal as promoting/including it into the standard library.

1 Like

This PR contains a number of features for constructing const generic arrays from iterators/fill/etc:

In particular the FromIterator<T> for Result<[T; N], FillError<T, N>> impl looks very handy for the sort of stuff I'm doing:

1 Like

I think the least scary version of this pattern (which also handles drop correctly) is a stack backed vector. I don't think the (OP) proposed api's will be necessary though.

2 Likes

There's a PR open for this already; it's just called generate:

(Which of course is a name I like for it.)

5 Likes

Sorry i have not found it at first.