Skip to content

Commit 6a69850

Browse files
committed
Rewrite try to be written in terms of the Try trait
This rewrites the section to say that it uses the `Try` trait. I felt it was a bit too awkward to avoid it (since it is unstable). This keeps an explicit list of the types that the `Try` trait is implemented for, and adds the missing types (like `ControlFlow`). The intent is that when `Try` is stabilized that the desuggaring note moves to a normative rule, the `expr.try.restricted-types` rule is removed (and instead direct the user to the standard library documentation). I'm still holding out hope that they change the terminology, since I think the current choice is going to be confusing. This has a hack to allow `feature(try_trait_v2)` by abusing the style checker by adding some spaces. I really wanted to keep this example tested to ensure that it is kept up-to-date. However, I may regret this in the future. Fixes #1927
1 parent 7e7f89a commit 6a69850

File tree

1 file changed

+41
-25
lines changed

1 file changed

+41
-25
lines changed

src/expressions/operator-expr.md

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -198,16 +198,16 @@ TryPropagationExpression -> Expression `?`
198198
```
199199

200200
r[expr.try.intro]
201-
The try propagation operator (`?`) unwraps valid values or returns erroneous values, propagating them to the calling function.
201+
The try propagation expression uses the value of the inner expression and the [`Try`][core::ops::Try] trait to decide whether to produce a value, and if so, what value to produce, or whether to return a value to the caller, and if so, what value to return.
202202

203203
> [!EXAMPLE]
204204
> The following examples illustrate some basic uses of the try propagation expression.
205205
>
206206
> ```rust
207207
> # use std::num::ParseIntError;
208208
> fn try_to_parse() -> Result<i32, ParseIntError> {
209-
> let x: i32 = "123".parse()?; // x = 123
210-
> let y: i32 = "24a".parse()?; // returns an Err() immediately
209+
> let x: i32 = "123".parse()?; // `x` is `123`.
210+
> let y: i32 = "24a".parse()?; // Returns an `Err()` immediately.
211211
> Ok(x + y) // Doesn't run.
212212
> }
213213
>
@@ -269,32 +269,48 @@ The try propagation operator (`?`) unwraps valid values or returns erroneous val
269269
> # }
270270
> ```
271271
272+
> [!NOTE]
273+
> The [`core::ops::Try`] trait is currently unstable, and thus cannot be implemented for user types without using the nightly release channel.
274+
>
275+
> The try propagation expression is currently roughly equivalent to:
276+
>
277+
> ```rust
278+
> # #![ feature(try_trait_v2) ]
279+
> # fn example() -> Result<(), ()> {
280+
> # let expr = Ok(());
281+
> match core::ops::Try::branch(expr) {
282+
> core::ops::ControlFlow::Continue(val) => val,
283+
> core::ops::ControlFlow::Break(residual) =>
284+
> return core::ops::FromResidual::from_residual(residual),
285+
> }
286+
> # Ok(())
287+
> # }
288+
> ```
289+
272290
> [!NOTE]
273291
> The try propagation operator is sometimes called *the question mark operator*, *the `?` operator*, or *the try operator*.
274292
275293
r[expr.try.restricted-types]
276-
It is a unary postfix operator that can only be applied to the types `Result<T, E>` and `Option<T>`.
277-
278-
r[expr.try.behavior-std-result]
279-
When applied to values of the `Result<T, E>` type, it propagates errors.
280-
281-
r[expr.try.effects-err]
282-
If the value is `Err(e)`, then it will return `Err(From::from(e))` from the enclosing function or closure.
283-
284-
r[expr.try.result-ok]
285-
If applied to `Ok(x)`, then it will unwrap the value to evaluate to `x`.
286-
287-
r[expr.try.behavior-std-option]
288-
When applied to values of the `Option<T>` type, it propagates `None`s.
289-
290-
r[expr.try.effects-none]
291-
If the value is `None`, then it will return `None`.
292-
293-
r[expr.try.result-some]
294-
If applied to `Some(x)`, then it will unwrap the value to evaluate to `x`.
295-
296-
r[expr.try.trait]
297-
`?` cannot be overloaded.
294+
The try propagation operator can be applied to expressions with the type of:
295+
296+
- [`Result<T, E>`]
297+
- `Result::Ok(val)` evaluates to the value of `val`.
298+
- `Result::Err(e)` returns the value `Result::Err(From::from(e))`.
299+
- [`Option<T>`]
300+
- `Option::Some(val)` evaluates to the value of `val`.
301+
- `Option::None` returns the value `Option::None`.
302+
- [`ControlFlow<B, C>`][core::ops::ControlFlow]
303+
- `ControlFlow::Continue(c)` evaluates to value of `c`.
304+
- `ControlFlow::Break(b)` returns the value `ControlFlow::Break(b)`.
305+
- [`Poll<Result<T, E>>`][core::task::Poll]
306+
- `Poll::Ready(Ok(val))` evaluates to the value `Poll::Ready(val)`.
307+
- `Poll::Ready(Err(e))` returns the value `Poll::Ready(Err(From::from(e)))`.
308+
- `Poll::Pending` evaluates to the value `Poll::Pending`.
309+
- [`Poll<Option<Result<T, E>>>`][`core::task::Poll`]
310+
- `Poll::Ready(Some(Ok(val)))` evaluates to the value `Poll::Ready(Some(val))`.
311+
- `Poll::Ready(Some(Err(e)))` returns the value `Poll::Ready(Some(Err(From::from(e))))`.
312+
- `Poll::Ready(None)` evaluates to the value `Poll::Ready(None)`.
313+
- `Poll::Pending` evaluates to the value `Poll::Pending`.
298314
299315
r[expr.negate]
300316
## Negation operators

0 commit comments

Comments
 (0)