Live data from Hacker News

A final proposal for Rust await syntax

boats.gitlab.io

191–200 of 265 posts

Re: A final proposal for Rust await syntax

#191
post #29

Earlier quoted context omitted.

Do notation solves that problem!

Came here to say that. I think do notation (and applicative idioms) are easily one of the most-underappreciated features outside the Haskell community.

Scala has had monadic do-notation (called 'for-comprehensions') for a long time and OCaml has recently gained both monadic and applicative 'do notation' (called various things, but mostly 'let+ syntax'). Edit: Oh and F# has also had computation expressions for a long time.

Re: A final proposal for Rust await syntax

#192
post #176

Earlier quoted context omitted.

It is inconsistent to hold those beliefs. Because "insane" implies that the Rust team made wrong decisions with the syntax, in fact so obviously wrong that no "sane" person would make them. If you acknowledge that the syntax decisions make sense, then they aren't "insane".

Meh. That's just playing semantic games. I'm using "insane" in IMHO the more common colloquial sense of "inscrutable; hard to understand; inconsistent with existing paradigms". I'm absolutely not questioning your mental health. Nothing about the soundness of your design means that Rust isn't hard to learn, is all I'm saying. And per the freakshow all around us, it's getting harder, not easier.

I've never understood the use of the word "semantic" in the dismissive sense. Meaning is everything when parties are trying to communicate. This thread finally got to the heart of the miscommunication, and instead of celebrating you say "meh." I don't get it.

Re: A final proposal for Rust await syntax

#193
post #100
post #13

The designers of Kotlin also had an interesting point: await (synchronous call) should be the default, non-awaited (asynchronous) code should have a keyword indicating that it is async.

This would have been my favorite approach, and there was a discussion about doing it in Rust: https://internals.rust-lang.org/t/explicit-future-constructi... There were two main objections: First, a Rust async function like this (using explicit lifetime annotations for exposition purposes only, normally they would be elided)... async fn f (r: &'a i32) -> i32 { ... *r ... } ...desugars to a sync function whose return…

I wonder about an altenate timeline where Rust kept its lightweight threads. Marking async calls explicitly instead of marking synchronous calls with await is a step in that direction, because that's also the syntax you have with lightweight threads. What would problem 1 look like in that alternate timeline?

In that case the concept of async functions disappears and your first function becomes a normal function. The second function remains a Future building function. So I'm tempted to conclude that this problem might be a non-problem, caused by a confusion between async functions and Future building functions. Even though an async function desugars to a Future building function, they are conceptually distinct in the lightweight threads model. With lightweight threads, all functions are async functions. A future building function explicitly builds a delayed computation. The types should be different.

An async function is just like a normal function, except that it may call async APIs (i.e. other async functions). Calling an async function from a normal function is an error; it does not return a future. The programmer never sees that async functions are implemented with Futures under the hood. In particular, an async function is not syntactic sugar for wrapping its body in an async block. We rename the async { ... } keyword to future { ... }, which constructs a future out of the block. You may call async functions in a future block. So if you want to call an async function inside a normal function, you must do future { foo() }, making it syntactically clear that the call is delayed even when the call is made from inside a normal function. The programmer no longer needs to think about how async functions work at all. Don't tell them that future{ foo() } actually will just call foo(), and foo() returns the future, they don't need to know that. The only thing they need to remember is that async functions can only be called from within async functions or future blocks. In all other respects they behave the same as normal functions. All delaying of computation and running computation in parallel is explicit.

IMO, problem 1 only occurs to programmers that have been told that async fn = Future returning function. That's a leaky abstraction; it's syntactic sugar. If you prevent them from developing this notion, the problem simply doesn't occur. To understand the main proposal for async/await you basically have to understand what desugaring the compiler is doing. With the "Explicit future construction, implicit await" you can use async functions and futures without understanding how they work under the hood. It's a non-leaky abstraction.

IMO, problem 2 is a problem for the IDE. The IDE can easily show which function calls are async and which are not.

Re: A final proposal for Rust await syntax

#194
post #105
post #29

Earlier quoted context omitted.

Do notation solves that problem!

Do notation does not solve that problem. It solves the problem of chaining `.and_then` calls, but this is one layer up- do notation would still require each of those awaits to be a separate `a <- b` "statement," which couldn't even be chained in the first place!

Yes, exactly, bindings shouldn't be chained. The whole point of do-notation i.e. syntax that looks like normal bindings is to make them look imperative so that our monkey brains can grok concurrent code easily. Making 'await' expression-oriented is missing the whole point of 'await'. You could have just kept using 'flat_map' or whatever macro.

Re: A final proposal for Rust await syntax

#195
post #109
post #55

Earlier quoted context omitted.

> Rust is already a weird language to come to from the likes of python, Java, or Javascript Every time I see a statement like this, I remember a (paraphrased) statement from Rich Hickey: "[musical] instruments are made for people who can play them!". I think unless you are specifically designing a beginner language (like Scratch), you should not take into consideration "ease of use" or "familiarity" arguments.

I wouldn't use a programming language whose designer had this attitude.

And I wouldn't use a programming language whose designer didn't have this attitude.

I also wouldn't use a programming language that is optimized for increasing the number of users at the expense of performance, clarity, stability, consistency, or power. I don't want a language that appeals to most people, I want one that disproportionately appeals to careful and competent people.

Re: A final proposal for Rust await syntax

#196

Earlier quoted context omitted.

See, now this is exactly my issue with this syntax, I generally expect to be able to "chain" things with the "." notation.

You can chain .await, though. let n = future_of_future_of_int .await .await;

True, but you can't chain returns, making this suggested use of a special postfix operation a bad idea imo.

Re: A final proposal for Rust await syntax

#197
post #123
post #86

Earlier quoted context omitted.

It does not necessarily mean a lack of trust. It could be different incentives or priorities. For example, some users might desire major redesigns of past work but not bear the cost of the rework. As such, they might perceive some small improvement without any (direct) cost. Personally, I think some groups have moved so far in the direction of community involvement that they forget the practical implications of diver…

Could you please give some examples? I think I follow Rust pretty well, but have no idea what/which-improvements/who/which-groups you could mean.

I don't want to name any particular people or groups, because everyone makes mistakes and has limitations.

I will say this: in my personal experience, I've been a part of groups that struggle in dealing with complex decisions. Many times they get bogged down when they don't find a clear answer that satisfies everyone or all criteria. In many cases, such groups don't have a clear leader or the leader lacks the skills, experience, and character to do what is necessary; namely, choose (and communicate) the least-worst decision that keeps the ball moving forward.

In such cases, it is not necessary (and unrealistic to expect) that everyone agree with every aspect of every decision. A leader needs confidence and persistence to make tough decisions, as opposed to abdicating leadership. Some examples of the latter include (1) ignoring a choice until some default decision is made implicitly or (2) simply choosing the idea from the most vocal person.

Put more broadly, in this context, leaders must balance four aspects: (a) scoping and framing a decision; (b) gathering diverse points of view; (c) building some degree of consensus or buy-in; and (d) making a decision. It appears to me that the Rust language team handled all four comprehensively.

Re: A final proposal for Rust await syntax

#198
post #183

Earlier quoted context omitted.

IMO it's awkward for the following reasons: (1) It looks like a field access, and field accesses are "cheap", method invocations aren't. This breaks the 'conceptual weight' model when you look at a line of code. Field accesses are simple and understood. It becomes impossible to gauge the 'cost' of a line by looking at it unless you're intimately familiar with the workings of 'await' and there's no visual cue. (2) If…

> (2) If we create new such postfix operators in the future we'll have to break yet more source code by reserving yet more field names in all structs in all existing code. This is already the case; all keywords in Rust are reserved keywords, not contextual keywords, so you already can't have a field named, say, `return`, despite the fact that a hypothetical `foo.return` would otherwise be unambiguous. Further, with t…

> This is already the case; all keywords in Rust are reserved keywords, not contextual keywords, so you already can't have a field named, say, `return`, despite the fact that a hypothetical `foo.return` would otherwise be unambiguous. Further, with the Edition system and rustfmt, reserving keywords in this manner shouldn't be disruptive.

Well, the keyword could instead be "@await" instead of "await" meaning that no regressions would be introduced with field names, either now or in the future, right? Unless I'm mistaken, the '@' character isn't a valid prefix for an identifier.

> The paragraph at the end of the OP suggests that the language team is seeking to propose allowing certain other keywords (specifically those that can return useful values) to be used in postfix position (which implies that `await` could then be used in prefix position as well), which could e.g. (I'm spitballing here) replace the `.for_each()` method on iterators with just `.for`.

That's fine, I guess, but then we'd have yet more keywords we can't use. However, "@for" would not break anything. FWIW the way I read that section, the proposal enjoys little support.

Re: A final proposal for Rust await syntax

#199
post #172

Earlier quoted context omitted.

Not as things are currently designed. This is similar to how you can’t use things like the `?` operator, break, return, etc. inside a lambda and expect it to affect the outer function: it doesn’t work because lambdas are treated as their own functions. Personally I think it would be cool to pursue an extension to lambdas that would allow some of those things to work, but I’m not a Rust team member or anything, just a…

Technically, `?` can work in lambda's if the return value is a `Result` - though it won't work like it's being called as part of a normal loop or whatever. That's largely mitigated by the combinators available on an interator of `Result`s. So I think we'll just need similar tooling for lambdas - perhaps an `async` modifier for them? That (I think) would lift await stuff up to `?` in terms of lambda support.

Yep, and in fact async lambdas are already a thing on nightly. But, while I may just be nitpicking, `.map(async |f| f.await)` wouldn't do anything useful. Applied to an Iterator of Futures, it would be a no-op, kind of like (since you mentioned `?`) `.map(|x| Ok(x?)). Instead you'd probably want some combinator to turn it into whatever "Iterator but async" trait Rust eventually standardizes on – futures-rs has Stream for this purpose, but std doesn't have anything yet. That trait would have its own collect() method which would return a Future>, and you'd then await on that.

Yeah, I guess I'm nitpicking.

Re: A final proposal for Rust await syntax

#200
post #79

Earlier quoted context omitted.

> Obviously core devs of Google backed language cannot do better. They can only gain that trust from users within Google, not outside of Google. That's a non sequitur. Trust is not mandated by company boundaries. I for one trust in the competence of the Go maintainers, while at the same time having absolutely zero trust in Google as a company.

> I for one trust in the competence of the Go maintainers That's fine. But ultimately Go employees do not work for you and cannot put much effort into proving they are good at solving problems for you, since the company doesn't pay them to do it. There will not be a track record in users eyes of their design decisions and not much trust from users they are even capable of doing it well.

If they're paying people to develop tools for solving general purpose computing problems and presenting those tools out in the open, then they are doing something that is good for everyone.
Post reply on HN