#temporary #value #lifetime #reference

no-std temporaries

Make temporary values useable in a fairly normal style through macros. This nicely wraps the hacks that work around temporaries’ limitations.

1 unstable release

0.10.0 Nov 14, 2024

#274 in Programming languages

Download history 65/week @ 2024-11-08 50/week @ 2024-11-15 4/week @ 2024-11-22 9/week @ 2024-11-29 4/week @ 2024-12-06

132 downloads per month

MIT/Apache

13KB
161 lines

Make temporary values useable in a fairly normal style through macros. This nicely wraps the hacks that work around temporaries’ limitations. This crate is itself hopefully temporary, until Rust can natively solve the problem.

What Problem does this Solve?

Normally let str = &String::from("str"); shouldn’t compile. The inner String object should be dropped at the end of the statement, leaving a dangling reference. However, in simple cases like this, Rust gives you a pass, by extending the lifetime. Alas this has not yet been generalised. You can often work around that, by storing the temporary value in a separate variable.

The same situation arises, when the temporary value is hidden. Only, then you have no influence to work around it. This is famously the case with format_args!, the efficient alternative to heap-allocated format!. This strongly limits its usefulness – or did, without these macros!

Returning a temporary value from a simple block also benefits from lifetime extension. Again this is not yet the case for more complex blocks, like if or match. Since Rust doesn’t have a ? : operator, that prevents dynamic choice involving temporaries. So, these fail to compile, showing both explicit and hidden temporaries in the 1st case:

// `x` & `y` would live longer than the `String` and `format_args`’ hidden temporary.
let x = &vec![&String::from("x")];
let y = format_args!("1 + 2 = {}", 1 + 2);

// Consuming the value directly in `print!()` would be ok, were it not for the man in the middle, `if`.
print!("{}", if 1 < 1 {
    format_args!("1 + 2 = {}", 1 + 2)
} else {
    format_args!("1 + 3 = {}", 1 + 3)
});

The Solution

The let problem is solved by turning it into a match, making the value live as long as the following code. Multiple choice is achieved by breaking from a tuple. Both of these are not nice to look at. Therefore temporaries wraps them up in convenient macros.

This only applies to local processing. Returning a temporary value from a closure or function is alas not something a macro can achieve. That requires a language change, such as super let, which is under discussion.

This was inspired by this & this. There is a similar crate, which, unlike this one, needs a proc-macro, hoist_temporaries.

No runtime deps