Array constructor for Clone types

I have run across this problem where I want to make an array (fixed size) using a constructor where the type implements Clone but not Copy.

I know that it is possible to use Default (if that exists for the type) and then overwrite each index but that can be either messy at best or impossible at worst.

So it there any reason why the following shouldn't exist? (assuming T is actually a concrete type)

fn array_6<T: Clone>() -> [T; 6] {
    [T::new(); 6]
}

I'm not understanding the question. T::new() is not a method on the Clone trait. The concrete type behind T may not have a new() method. It's not possible to magically synthesize a new() method for an arbitrary type, since the compiler has no idea what invariants might apply to the type's internal state. You can't build new() out of clone() since clone() requires a value of T to already exist.

So, how could this work without an additional trait bound like Default?

Sorry, that is my fault. I didn't explain this very well.

The following fails:

fn foo() -> [Vec<i32>; 6] {
    [vec![1, 2]; 6]
}

With:

the trait `std::marker::Copy` is not implemented for `std::vec::Vec<i32>`

= note: the `Copy` trait is required because the repeated element will be copied

Ah, that makes sense.

I don't have any citations for this, but my impression is that potentially expensive copies (i.e., excluding Clone impls for Copy types) are intentionally never permitted without some explicit syntactic marker at the clone site. Which I generally agree with.

But I do think it would be silly to demand N separate syntactic markers whenever N clones happen at "the same place" like this. I don't see anything like this in std already, and I haven't heard of a crate for this, so here's one strawman idea that I would endorse:

[Vec<i32>; 6]::from_clones_of(vec![1,2]);

That would require const generics which probably is fine.

But I disagree in a place like this that implicitly cloning is bad.

The similar vec![expr; N] does use Clone. I guess you can attribute this design difference to the different teams involved, being a language or library feature.

URLO had a thread about the same thing recently:

1 Like

I guess it's the partial drop on panics that make this harder for arrays, whereas vec! naturally knows the length written so far.

Almost every question "why don't arrays just…?" is because arrays in Rust are half-baked. There's no profound reason. They just can't be improved much until Rust finalizes the const generics feature.

In the meantime you can use wrappers on arrays that make them a little bit more usable, e.g.:

2 Likes

But the following works:

let arr = [
    vec![1, 2],
    vec![1, 2],
    vec![1, 2],
    vec![1, 2],
    vec![1, 2],
    vec![1, 2],
];

Note that it isn't equivalent to one that uses clone; that'd be

let tmp = vec![1, 2];
let _ = [
    tmp.clone(),
    tmp.clone(),
    tmp.clone(),
    tmp.clone(),
    tmp.clone(),
    tmp,
];

This will be a trivial helper once we have const generics; in the mean time, you could potentially make a macro for it if you can accept using weird number representations.