5 ms·
Please don't do that. I had to look several times to rewrite it as var temp1 = await StartRequest(); var temp2 = await temp1.GetBody(); var value =
by mdpopescu 7y ago
Please don't do that. I had to look several times to rewrite it as
var temp1 = await StartRequest();
var temp2 = await temp1.GetBody();
var value = temp2.Root;
which is instantly grokked.
- steveklabnik 7y agoThis is a great example of why syntax and semantics can't be separated. This works great in GC'd languages, but in Rust, these two things may not be equivalent. With the distinction between owned and temporary values, this may change the lifetime of what stuff is in scope and when. This is reduced a bit with non-lexical lifetimes, but it's not, strictly speaking, actually equivalent.
- nemothekid 7y agoI think this is a good example to show people who are on the fence about postfix then. I haven't felt strongly about postfix, but this is an eye opener for me.
- hombre_fatal 7y agoIt's a better case for showing how to use .map().
- steveklabnik 7y agoYeah, I think the trick is that the theory and practice might be the same. And usually, it's the other way around; spreading it out makes it work, whereas it may not otherwise. For example: 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.
- iknowstuff 7y agoThis has surprised me on occasion. Shouldn't the compiler be smart enough to figure out how long to keep it around for, instead of failing to compile?
- steveklabnik 7y agoOne could argue that the compiler could transform this for you. But systems languages are also about control. For someone versed in the way things are supposed to work, an owned value living longer than it should is surprising. Tradeoffs, tradeoffs.
- tylerhou 7y agoThe compiler is smart enough to deduce lifetimes — that’s why it can throw a compile error — but fixing them (auto-keeping temporaries) might introduce extra memory consumption/leaks that the programmer did not intend. Requiring the programmer to explicitly assign a temporary to a variable makes the programmer’s intent more clear. 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 https://abseil.io/tips/101 .)
- seppel 7y agoI totally get where you coming from, and even in non GC'd languages such as C++ lifetimes are extended (or not...) when you break down expression. 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.
- steveklabnik 7y agoI do too, which is why I preferred prefix await.
- oconnor663 7y agoThere are a few different ways I feel about this at the same time: - On the one hand, I agree that "interesting" operations really should be on their own lines. I think I'm going to strongly prefer to keep it to one `await` per line for the foreseeable future. - On the other hand, I know that many programmers will cram a lot of operations into one line if they can, and when that inevitably happens it would be nice for it to be readable. - And maybe in the long run, it's possible that a big, mature async ecosystem might make a lot of these operations so commonplace that they aren't "interesting" anymore. Maybe in that world we'll be glad to have a syntax that makes it easy to chain things together.
- skywhopper 7y agoThis is to my eyes far more cluttered and confusing than: var value = StartRequest().await.GetBody().await.Root; Or if you prefer multiline: var value = StartRequest().await. GetBody().await. Root;
- deleted 7y ago[deleted]