Performance between tuple and array

fn main() { let t = (||print!("h"), ||println!("hello world")); }It compiles. After I changed this code to use array,

fn main() { let t = [||print!("h"), ||println!("hello world")]; }it also compiles. So which has better performance?

1 Like

The performance is the same.

5 Likes

Doesn’t matter

In general the performance between using tuples and arrays should always be comparable (in cases where both can be used in the same manner).

In your concrete case, the main function does absolutely nothing in either case, and will be optimized away completely.

7 Likes

On rust.godbolt.org, if you add -O to flags, you can check how optimized code looks like.

In this case both functions are exactly identical — entirely empty.

3 Likes

Wait a minute, what is going on here? How are you getting those closures into that array? I thought this was impossible because all elements of an array should be the same type but "no two closures, even if identical, have the same type" as the compiler says.

I'm now curious why this:

    let mut closures = vec![];
    closures.push(|| println!("Hello "));
    closures.push(|| println!("world!"));

fails to compile with error:

closures.push(|| println!("world!"));
     |              ---- ^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
...
note: no two closures, even if identical, have the same type

However I can get those same two closures into arrays and vectors, including pushing into vectors, with this:

    // An array of closures.
    let mut closures = [|| print!("Hello "), || println!("world!")];
    for closure in &closures {
        closure();
    }

    // Which we can assign to
    closures[0] = || print!("xxx ");
    closures[1] = || println!("yyy");
    for closure in &closures {
        closure();
    }

    // A Vector of closures assigned from an array.
    let mut closures = vec![];
    closures = [|| print!("Hello "), || println!("world!")].to_vec();
    for closure in &closures {
        closure();
    }
    // Which we can push into
    closures.push(|| print!("xxx"));
    closures.push(|| println!("yyy"));
    for closure in &closures {
        closure();
    }

    // A Vector initialized from an array closures.
    let mut closures = Vec::from([|| print!("Hello "), || println!("world!")]);
    for closure in &closures {
        closure();
    }
    // Which we can also push() into
    closures.push(|| print!("xxx "));
    closures.push(|| println!("yyy"));
    for closure in &closures {
        closure();
    }

Which compiles and runs just fine.

In the OP they're coercing to function pointers. With the nonworking vector, the compiler infers a closure type instead. You could fix it with a type annotation.

1 Like

So I can:

    let mut closures: Vec<fn()> = vec![];
    closures.push(|| println!("Hello "));
    closures.push(|| println!("world!"));
    for closure in &closures {
        closure();
    }

Well I never. Sneaky things these coercion's. Thanks.

2 Likes

Tuples and arrays are essentially identical in performance. Use whichever best fits the problem you're trying to solve.

Well, except that Hash on arrays is slightly slower than on tuples.

2 Likes

This line is too small.

Well… if you don’t Hash the thing, then the difference won’t matter.

In case you’re interested why it’s “slower” for arrays: when hashing an array, the size of the error is fed into the hash function alongside the elements, whereas tuples only feed the elements. This is technically slower, since more data is hashed, but also, realistically, it’s not a lot slower, especially for longer arrays, or arrays with large[1] items, the difference becomes relatively small.

The reason why this is done is so that hashing of arrays can stay compatible with hashing of slices as required for this Borrow implementation; this allows a &[T] to be used to index into a HashMap<[T; 32], _> for example. And hashing of slices needs to include length information because slices are not fixed-length.


  1. in terms of amount of information that needs to be hashed ↩︎

7 Likes

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.