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.
A final proposal for Rust await syntax
191–200 of 265 posts
Re: A final proposal for Rust await syntax
#192Earlier 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.
Re: A final proposal for Rust await syntax
#193The 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…
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
#194Earlier 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!
Re: A final proposal for Rust await syntax
#195Earlier 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.
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
#196Earlier 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;
Re: A final proposal for Rust await syntax
#197Earlier 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 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
#198Earlier 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…
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
#199Earlier 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.
Yeah, I guess I'm nitpicking.
Re: A final proposal for Rust await syntax
#200Earlier 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.