Skip to content

Commit 61f349c

Browse files
ehusstraviscross
authored andcommitted
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 72aab3e commit 61f349c

File tree

1 file changed

+40
-23
lines changed

1 file changed

+40
-23
lines changed

src/expressions/operator-expr.md

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ 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`] 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.
@@ -269,32 +269,48 @@ The try propagation operator (`?`) unwraps valid values or returns erroneous val
269269
> # }
270270
> ```
271271
272+
> [!NOTE]
273+
> The [`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
@@ -928,6 +944,7 @@ Like assignment expressions, compound assignment expressions always produce [the
928944
> Try not to write code that depends on the evaluation order of operands in compound assignment expressions.
929945
> See [this test] for an example of using this dependency.
930946
947+
[`Try`]: core::ops::Try
931948
[copies or moves]: ../expressions.md#moved-and-copied-types
932949
[dropping]: ../destructors.md
933950
[explicit discriminants]: ../items/enumerations.md#explicit-discriminants

0 commit comments

Comments
 (0)