Earlier quoted context omitted.
> `foo.bar.qux.qaz.await!()` would need to expand to `await { foo.bar.qux.qaz }` Interesting point, thank you. I hadn't seen this previously mentioned, and it's definitely a reasonable argument. > there's no denying that `foo.await?.bar` appears nicer than `foo.await!()?.bar`, especially if there is no guarantee that postfix macros will ever become a thing. Agreed, for sure. I'm honestly just very concerned about the…
No problem. :) I was actually in the same camp as you until, in the wake of boats' prior post on await syntax, I sat down and got well into writing an RFC for postfix macros until I stumbled upon the parsing concern and shelved it under the category of "not nearly as trivial as I thought it would be".
Update on await syntax in Rust
171–180 of 199 posts
Re: Update on await syntax in Rust
#172Earlier quoted context omitted.
> There's no hint in that expression that it's anything other than a method call. Compared with `fut.await`... > There's no hint in that expression that it's anything other than a field access. At least there is precedence for functions to have magical compiler-ness for 'doing stuff', instead of overloading field access which is one of the simplest operations you can have. > ... requires knowing the type of `fut` ...…
If it's a method you should be able to create a vector of futures and `.map(Future::await)` or even `.map(Future::await as FnMut(_) -> _)`. Clearly this would never work, since `await` is implement by transforming the containing function into a state machine, your suggestion would make this impossible.
let newvec = vec![fut1, fut2, fut3].map(Future::await).collect()
would be equivalent to let f1 = fut1.await();
let f2 = fut2.await();
let f3 = fut3.await();
let newvec = vec![f1,f2,f3];
or vec![fut1,fut2,fut3].map(|fut| fut.await).collect()Re: Update on await syntax in Rust
#173Re: Update on await syntax in Rust
#174Earlier quoted context omitted.
This 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.
I 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…
Re: Update on await syntax in Rust
#175Earlier quoted context omitted.
This just then boils down to saying "the await keyword should have required parens after it", which is a different argument than saying "it should be a lang item".
hell, I'd support that. A function/method 'does a thing' while field access 'reads a thing'. Rust doesn't have implicit getters and setters like Python might have. It doesn't LOOK like `fut.await` should/could DO anything, but it can.
Having said that, I'd have to assume that `fut.await` does consume the future, which normal field access doesn't do. Personally, I'm ok with the tradeoff that says "this keyword looks like field access but it consumes the receiver, but as a result we don't have these extra parens all over the place on a keyword", especially because going the other way introduces other costs (e.g. it looks like a method call and yet can't be referred to as Future::await).
Re: Update on await syntax in Rust
#176Earlier quoted context omitted.
I think it's totally reasonable to judge a road surface based on how effective it is, in practice, with the kinds of traffic that will be travelling on it. Traction control is a part of that landscape. Designing with awareness of syntax highlighting makes sense. But we should also keep an awareness that it won't always be there.
> I think it's totally reasonable to judge a road surface based on how effective it is, in practice, with the kinds of traffic that will be travelling on it. Yes, and if we outlawed the use of cars without traction control on certain roads, then I would be fine with designing with the assumption traction control will be on. But as long as you allow older cars without traction control to still drive on the road, you a…
A nitpick:
> But as long as you allow older cars without traction control to still drive on the road, you are making the roads less safe for a certain percentage or class of drivers.
Probably. But if a sufficient fraction of cars have traction control, and we sufficiently improve the performance of traction controlled tires at sufficiently small damage to the performance of other tires, the reduction in the threat of being hit by cars with traction control will outweigh the increase in risk of losing control for those cars without, even before trading off risk between cars (which is certainly more complicated).
I don't think there's a direct mapping back to syntax and highlighting.
Re: Update on await syntax in Rust
#177Question for people more familiar with async/await semantics, how do you typically control what thread the async procedure runs on? Having spent a lot of time now in rxJava and really getting into the power of stream processing and composition, it feels like async/await is almost too simplistic.
You typically don't, as knowing which physical thread you're running in is (thankfully) becoming a relic of the past.
Re: Update on await syntax in Rust
#178Earlier quoted context omitted.
If it's a method you should be able to create a vector of futures and `.map(Future::await)` or even `.map(Future::await as FnMut(_) -> _)`. Clearly this would never work, since `await` is implement by transforming the containing function into a state machine, your suggestion would make this impossible.
I mean, why couldn't it? let newvec = vec![fut1, fut2, fut3].map(Future::await).collect() would be equivalent to let f1 = fut1.await(); let f2 = fut2.await(); let f3 = fut3.await(); let newvec = vec![f1,f2,f3]; or vec![fut1,fut2,fut3].map(|fut| fut.await).collect()
Re: Update on await syntax in Rust
#179Question for people more familiar with async/await semantics, how do you typically control what thread the async procedure runs on? Having spent a lot of time now in rxJava and really getting into the power of stream processing and composition, it feels like async/await is almost too simplistic.
async/await produces a Future. In order for that Future to execute, you place it on an executor. It won't start executing until you do so. Which thread it runs on, and how, is all the executor's job. So the answer is basically "pick the executor which has the semantics you want".
Re: Update on await syntax in Rust
#180Question for people more familiar with async/await semantics, how do you typically control what thread the async procedure runs on? Having spent a lot of time now in rxJava and really getting into the power of stream processing and composition, it feels like async/await is almost too simplistic.
async/await produces a Future. In order for that Future to execute, you place it on an executor. It won't start executing until you do so. Which thread it runs on, and how, is all the executor's job. So the answer is basically "pick the executor which has the semantics you want".
Also if you use multiple modules with their own executors, they don't compose well. You can easily get oversubscription of CPUs.
Javascript's promises are self starting, which I would say is an improvement but the total lack of back pressure is anywhere from galling to highly problematic depending on the problem domain.
Goldilocks solution might be to have default executor behavior with an obvious and straightforward way to override it.