I’ve previously suggested implicit await, and more recently suggested non-chainable await.
The community seems very strongly in favor of explicit await
(I’d love for that to change, but…). However, the granularity of explicitness is what creates boilerplate (i.e. needing it many times in the same expression).
[Warning: the following suggestion will be controversial]
I’m curious if most of the community would compromise and allow “partial-implicit await”?
await response = client.get("https://my_api").send()?.json()?;
This is something akin to value de-structuring, which I’m calling expression de-structuring.
// Value de-structuring
let (a, b, c) = ...;
// De-sugars to:
let _abc = ...;
let a = _abc.0;
let b = _abc.1;
let c = _abc.2;
// Expression de-structuring
await response = client.get("https://my_api").send()?.json()?;
// De-sugards to:
// Using: prefix await with explicit precedence
// Since ? does not expect a Future, de-structure the expression at that point.
let response = await (client.get("https://my_api").send());
let response = await (response?.json());
let response = response?;
The compiler would need to do a bit more work, but nothing very magical. Iterate through the expression looking for when to split based on the sub expressions both using impl Future or not.
It also extends itself well to work with combinators or multiple futures if we so choose. E.g.
await with_combinator = client.get("https://my_api").send().and_then(parse_json)?;
// De-sugars to:
// Since .and_then expects a Future don't de-structure the expression at that point.
let with_combinator = await (client.get("https://my_api").send().and_then(parse_json));
let with_combinator = with_combinator?;
// If needed, given that the compiler knows these expressions a, b are independent,
// each of the expressions would be de-structured independently.
await (a, b) = (
client.get("https://my_api_a").send()?.json()?,
client.get("https://my_api_b").send()?.json()?,
);
// De-sugars to:
let a: impl Future = client.get("https://my_api_a").send();
let b: impl Future = client.get("https://my_api_b").send();
let (a, b) = (a.poll(), b.poll());
// return if either a or b is NotReady;
let a: impl Future = a?.json();
let b: impl Future = b?.json();
let (a, b) = (a.poll(), b.poll());
// return if either a or b is NotReady;
let (a, b) = (a?, b?);