`vec!` vs. `Vec::from()`

The usual way to initialise a vector is to use the macro vec!, eg.

struct Foo(i32);
let v1: Vec<Foo> = vec![Foo(23),Foo(42)];

However, one gets the same result by using vec::from():

let v1: Vec<Foo> = Vec::from([Foo(23),Foo(42)]);

I wonder if there is any advantage of using the macro (beside of saving five characters), e.g. in terms of performance or style?

1 Like

No, use whichever you prefer. They are exactly the same.

The macro may optimize better.

1 Like

The macro uses libstd's internal functions, and might generate more efficient code, and avoid putting arrays on the stack.

With from it depends on how smart LLVM is, and it hasn't always been smart about it.

3 Likes

Why is that?

It looks like in both cases the array will be Boxed and then converted into a Vec.

Using Vec::from:

impl<T, const N: usize> From<[T; N]> for Vec<T> {
    fn from(s: [T; N]) -> Vec<T> {
        <[T]>::into_vec(Box::new(s))
    }
}

Using vec!:

macro_rules! vec {
    ($($x:expr),+ $(,)?) => (
        $crate::__rust_force_expr!(<[_]>::into_vec(
            // This rustc_box is not required, but it produces a dramatic improvement in compile
            // time when constructing arrays with many elements.
            #[rustc_box]
            $crate::boxed::Box::new([$($x),+])
        ))
    );
}

Is the difference in the #[rustc_box] attribute?

Yes.

Thanks, but...

Box::new() already uses the attribute, so ultimately #[rustc_box] is used in both cases.

Also the comment in vec! mentions improvements in compile time, not (performance) optimizations.

What am I missing?

It uses the attribute internally, i.e. you still have a normal function call to Box::new that has to be optimized out. The attributed Box::new is basically a compiler intrinsic: Add #[rustc_box] and use it inside alloc by est31 · Pull Request #97293 · rust-lang/rust · GitHub

Box::new() is marked #[inline(always)]. Won't the call typically get inlined and same call generated when the argument is an array literal?

Although Vec::from([T; N]) isn't marked #[inline] (why?) so maybe not.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.