fn main() {
let world = gives_string().split(" ").next();
println!("{:?}", world);
}
fn gives_string() -> String {
String::from("hello world")
}
This will fail because the String is temporary, and we're trying to get a reference to it (via split), and so it would be deallocated at the end of the line, being a use-after-free. This, however, compiles: fn main() {
let world = gives_string();
let world = world.split(" ").next();
println!("{:?}", world);
}
fn gives_string() -> String {
String::from("hello world")
}
We're shadowing 'world', but the underlying String now lives to the end of main, so everything works, no more use-after free.I think before I'd want a good real-world example of where doing the multi-line thing goes wrong before I'd want to make an argument that this is why postfix is better.
A comparison: in C++, the behavior of auto-extending the lifetime of const references to temporaries (but not non-const references) is considered a wart in the language design. (Really, you should just assign a temporary to a value because the compiler can elide the copy. : https://abseil.io/tips/101 .)
Tradeoffs, tradeoffs.
However, I also strongly perfer to give these subexpressions names. That tremendously helps when debugging, logging, or just discussing the code with colleagues. In fact, these subexpressions do exist and they are a certain unit to reason about, especially when the program is not doing what it should. In these cases (and not only these) you really want to give them a canonical name and not only "line 42".
Maybe there should be a syntactical equivalent for named subexpressions.