3 ms·
> 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
by eximius 7y ago
> 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` ...
tbh, you don't need to know how await works. It goes and does stuff and returns a value. If you need to know what it does, you're looking up the types and seeing, 'oh its a future' and looking at that.
Contrast with the field access one and you don't even know its something else entirely.
I guess I just don't buy that it can't be a method. Like, formally, yea, it isn't a well-defined, safe Rust method. But make the impl
fn await(self: Self) -> Self::Target {
intrinsic::await(self)
}
Now its a method defined on the `Future` trait, it's discoverable, it's clearly magic, it's ergonomic... In my opinion, it beats the field access one in every conceivable metric.
It's just frustrating, I guess.
- Thiez 7y agoIf 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.
- eximius 7y agoI 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()
- Thiez 7y agoI think you fundamentally misunderstand async await. `vec[fut1, fut2, fut3].map(|fut| fut.await).collect()` will not do what you might expect, although I haven't bothered to read the RFC whether it will be allowed at all. Await must have compiler support and cannot just be some function you call.
- eximius 7y agoI am certainly being sloppy, though I think fundamentally misunderstanding it is a bit of an exaggeration. I know you can't await in a non-async function so, at the very least, you'd need (IDR the syntax for async closures?) vec![fut1, fut2, fut3].map_async(async|fut| fut.await).collect() I believe that could be built. Though, now I'm getting myself tripped up. Because I claimed that this is similar to vec![fut1, fut2, fut3].map(Future::await).collect() But I notice that I expect `await` to be a blocking, non-async function. Which, feels strange in that the lambda in the first block needs to be async but the function itself doesn't. > Await must have compiler support and cannot just be some function you call. I'm not saying it doesn't need compiler support. I explicitly state that it does - I just want the magic to be a little more explicit. Moreover, I believe that most programmers think of functions as 'encapsulated code', something that does a thing. In this sense, it matches what await does better than syntax that looks like it's accessing a field. Admittedly, in the purest sense of encapsulation, this method 'escapes' that encapsulation, but I don't consider that terribly important.
- eridius 7y ago> 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. Except we don't actually have precedence for "I'm going to declare a function, but it's not actually implemented in Rust, instead it's a cue to the compiler to do other magical stuff". Lang items are in fact the opposite; they're telling the compiler "here's the implementation for an extension point you've defined". For example the "panic_impl" lang item is a function that's invoked when code panics. The closest I can think of to what you're referring to is the fact that the type identified as "owned_box" has special dereferencing behavior, but that can be modeled as the compiler providing an implementation for an un-namable trait on the owned_box item where the trait represents the new deref behavior (just as how Deref and DerefMut represent the existing deref behaviors). > tbh, you don't need to know how await works. You need to know the type in order to determine if `fut.await()` is invoking this magical semantics-altering compiler behavior or if it's just invoking a method that happens to be named `await` (given that the lang_item proposal means await is no longer a keyword). > Contrast with the field access one and you don't even know its something else entirely. Except you do, because await is a keyword. It's impossible in Rust 2018 to have a field named await, and so any expression that looks like `x.await` is guaranteed to be an invocation of the await behavior. > I guess I just don't buy that it can't be a method. It cannot be a method that is implemented as a call to an intrinsic. The await keyword requires rewriting the function that invokes it.