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

make creating arrays of types that are not Copy less painful #1109

Closed
vks opened this issue May 7, 2015 · 12 comments
Closed

make creating arrays of types that are not Copy less painful #1109

vks opened this issue May 7, 2015 · 12 comments
Labels
T-lang Relevant to the language team, which will review and decide on the RFC.

Comments

@vks
Copy link

vks commented May 7, 2015

It would be very nice if

let array = [$expression; N];

was syntactic sugar for

let array = [$expression, $expression, $expression, ...];

This would allow things like

let bools = [AtomicBool::new(false); 10];
let array: [T; 10] = [Default::default(); 10];

Currently it only works for values that implement Copy. For the use case above, there is currently not really any alternative to just writing [$expr, $expr, ...].

I think this is a backwards-compatible change.

@vks
Copy link
Author

vks commented May 7, 2015

This is actually problematic regarding idempotency: Currently [rand(); 10] is not the same as [rand(), rand(), ...]. However, I still think we need an alternative to [AtomicBool::new(true), ...]. (Note that it cannot be implemented as a panic-safe macro AFAIK.)

@vks vks changed the title improve [value; N] sugar make creating arrays of types that are not Clone less painful May 7, 2015
@bluss
Copy link
Member

bluss commented May 7, 2015

I think you mean not Copy actually. Another good example is filling an array with None, where basically that particular enum variant "is Copy".

@vks vks changed the title make creating arrays of types that are not Clone less painful make creating arrays of types that are not Copy less painful May 7, 2015
@eddyb
Copy link
Member

eddyb commented May 7, 2015

The way I would do it is by supporting both Copy variables and any constants.
We have the qualification logic for constants, so this wouldn't be much of a hassle to implement.

In the case of constants, the "syntactic" expansion that you propose would be correct, as one could always write the same expression multiple times and it would result in the same value.
Though you still wouldn't be able to write [AtomicBool::new(false); N] without const fn.

@vks
Copy link
Author

vks commented May 7, 2015

Maybe we should have a new construct that is equivalent to [expr, expr, ...]. This macro [1] comes close, but is not panic-safe:

macro_rules! init_array(
    ($ty:ty, $len:expr, $val:expr) => (
        {
            let mut array: [$ty; $len] = unsafe { std::mem::uninitialized() };
            for i in array.iter_mut() {
                unsafe { ::std::ptr::write(i, $val); }
            }
            array
        }
    )
);

fn main() {
    let myarray = init_array!(AtomicBool, 10, AtomicBool::new(false));
}

[1] https://www.reddit.com/r/rust/comments/33xhhu/how_to_create_an_array_of_structs_that_havent/cqqf9tr

@eddyb
Copy link
Member

eddyb commented May 7, 2015

I would suggest not adding anything language-level because that usecase can be fulfilled with iterators and collecting to [T; N] when we get value parametrization in generics.

@vks
Copy link
Author

vks commented May 7, 2015

We still need to solve the panic-safeness problem, don't we?

@Kimundi
Copy link
Member

Kimundi commented May 7, 2015

With integer values in generics and #197 it would be possible to define a FixedSizeVec<T, N> which would be just as panic safe as a Vec<T>, and which can have a unwrap method for turning it into a [T; N]

@benw
Copy link

benw commented Jan 7, 2016

Re @eddyb's suggestion of supporting Copy variables or constants, that might still leave room for disappointment:

struct Foo;
let x = rand();
let array: [Result<u32, Foo>; 10] = [Ok(x); 10];

Ok(x) is not a constant, but it's still suitable to be copied into all the array elements.

@eddyb
Copy link
Member

eddyb commented Jan 7, 2016

@benw I guess the reformulation required there would be "ADT tree of Copy leaves" with e.g. None having no Copy leaf and Ok(x) having x: u32 as its only leaf, and u32 is Copy, so they would both work.

The only other kind of non-Copy values which can come from constants are &mut T, so this formulation alone, without the "or constants" I had, wouldn't allow for, e.g. [&mut []; 100].

But at least that's a backwards-compatible change to make later - and this "ADT tree of Copy leaves" can be checked in a simpler fashion than "or constant" (which requires moving the check to a later pass): traverse the HIR, recursing into struct/variant ctors (both Foo(...) and Bar {...} forms) and checking all other expressions' types for Copy.

@nrc nrc added the T-lang Relevant to the language team, which will review and decide on the RFC. label Aug 30, 2016
@ExpHP
Copy link

ExpHP commented Nov 7, 2017

Now that we have ::std::mem::ManuallyDrop, what's stopping us from having that Clone bound?

use ::std::mem::{uninitialized, ManuallyDrop};
use ::std::ptr;

macro_rules! yarr(
    ($val:expr; $len:expr)
    => {
        {
            // (this might panic... of consequence to nobody, anywhere)
            let x = $val;
            
            let array: [_; $len] = unsafe { uninitialized() };
            let mut array = ManuallyDrop::new(array);

            // (of course, one could micro-optimize this to do $n-1 clones...)
            for p in &mut *array {
                // clone() may panic, but if this occurs then the elements
                // of array will simply be leaked without risk of dropping
                // uninitialized data.
                unsafe { ::std::ptr::write(p, x.clone()); }
            }
            
            ManuallyDrop::into_inner(array)
        }
    };
)


fn main() {
    println!("{:?}", yarr!["Yo ho ho".to_string(); 3])
}

@leonardo-m
Copy link

A common need:

let mut m = [vec![]; 100];

@Centril
Copy link
Contributor

Centril commented Oct 7, 2018

Closing in favor of rust-lang/rust#49147 since that covers most of the use cases noted here.

@Centril Centril closed this as completed Oct 7, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-lang Relevant to the language team, which will review and decide on the RFC.
Projects
None yet
Development

No branches or pull requests

9 participants