this post was submitted on 08 Mar 2025
10 points (91.7% liked)

Rust Programming

8557 readers
7 users here now

founded 5 years ago
MODERATORS
10
Which is faster? (lemmings.world)
submitted 1 week ago* (last edited 1 week ago) by [email protected] to c/[email protected]
 
let mut variable: Type;
loop {
    variable = value;
}

or

loop {
    let variable: Type = value;
}
top 13 comments
sorted by: hot top controversial new old
[–] [email protected] 1 points 4 days ago

This is too simplistic example to give any meaningful answer. What’s Type? What’s value? If it’s i32 and 42 than they both compile to the exact same thing. But if Type is Drop than the second will call the destructor on each iteration. (I’ve also written previously about similar example with BorrowedBuf^1^).

[–] [email protected] 26 points 1 week ago

Side note, don't fall into the trap of premature optimization. You'll more than likely end up shooting yourself in the foot for something that usually doesn't matter in most cases.

[–] [email protected] 17 points 1 week ago

Functionally equivalent, the compiler will optimize lots for you. As the programmer, your focus should be on whether that variable is relevant to the loop's scope exclusively or not (i.e. if you need to access the variable after the loop has modified it). If not, keep it in the loop so that its easier to read your code.

[–] [email protected] 8 points 1 week ago* (last edited 1 week ago) (2 children)

I would say that they are equivalent. If I'm not mistaken, let statements only reserves space on the stack, and this only increments the stack register.

And on the latter snippet, the compiler would certainly not bother to modify the stack pointer as the type doesn't change.

[–] [email protected] 15 points 1 week ago* (last edited 1 week ago) (1 children)

according to godbolt: https://rust.godbolt.org/z/hP5Y3qMPW

use rand::random;

pub fn main1() {
    let mut var : u128;
    loop {
        var = random();
    }
}

pub fn main2() {
    loop {
        let var : u128 = random();
    }
}

compiles to:

example::main1::h45edf333d7832d08:
.Lfunc_begin8:
        sub     rsp, 24
.LBB8_1:
.Ltmp80:
        mov     rax, qword ptr [rip + rand::random::he3c23ceb967a3e28@GOTPCREL]
        call    rax
        mov     qword ptr [rsp + 8], rdx
        mov     qword ptr [rsp], rax
        jmp     .LBB8_1
.Ltmp81:
.Lfunc_end8:

example::main2::h1a899b25b96d66db:
.Lfunc_begin9:
        sub     rsp, 24
.LBB9_1:
.Ltmp82:
        mov     rax, qword ptr [rip + rand::random::he3c23ceb967a3e28@GOTPCREL]
        call    rax
        mov     qword ptr [rsp + 8], rdx
        mov     qword ptr [rsp], rax
        jmp     .LBB9_1
.Ltmp83:
.Lfunc_end9:
        jmp     .LBB9_1

So yeah, exactly the same thing.

[–] [email protected] 5 points 1 week ago

Fascinating! Thank you for sharing this.

[–] [email protected] 3 points 1 week ago* (last edited 1 week ago) (1 children)

let statements only reserves space on the stack

It is not guaranteed to do that. It could also use a register or be optimized out completly (like in the example you posted in the other comment).

The stack pointer is also not changed for each local variable, but instead for each function call, so it wouldn't make a difference anyway.

[–] [email protected] 1 points 1 week ago

Ok! Thanks for the clarification !

[–] [email protected] 2 points 1 week ago

Without context, there's no reason to compare the performance of these. The compiler is complex enough that what you do in the loop and after the loop matters with regards to optimizations.

Do you have more context? What's actually happening in the code?