Rust now has sub-expression elimination with automatic pure function identification:
#[inline(never)]
fn foo(a: usize) -> usize {
a + 1
}
#[unsafe(no_mangle)]
fn bar(a: usize) -> usize {
let a1 = foo(a);
let a2 = foo(a);
a1 + a2
}
foo does not have any side-effects (which is called "pure" function in some places). As a result, the generated bar is highly optimized (see this playground link), the two foo invocations are eliminated to one:
bar:
pushq %rax
callq playground::foo
addq %rax, %rax
popq %rcx
retq
However, this optimization can be disabled by some unnoticed practice:
fn foo(a: usize) -> usize {
if a > 2 {
a
} else {
panic!("")
}
}
If we add panic in the foo function, the generated bar will become (see this playground link):
bar:
pushq %rbx
movq %rdi, %rbx
callq playground::foo
movq %rbx, %rdi
callq playground::foo
addq %rbx, %rbx
movq %rbx, %rax
popq %rbx
retq
The reason is very straightforward and easy to understand: the panicking itself has side effect, so foo is not pure anymore.
Although this is reasonable enough, when we actually coding, I don't think most people will be aware that a simple unwrap or log::info! would disable this optimization. And moreover, in most stituations, this optimization should still be enabled in these situations.
As a result, I think a pure annotation would be helpful if people want to manually mark a function as pure, even if it has side-effects like unwrap or log.
There is a similar post, however, it was questioned about the necessity and motivation. (In my understanding, if we design this annotation as an unsafe attribute, we can even get rid of the complicated rules introduced in that post.)