From 6a0356834a51a31567883c58e2d89148a97ce8d0 Mon Sep 17 00:00:00 2001 From: "Havvy (Ryan Scheel)" Date: Sat, 21 Nov 2020 00:14:58 -0800 Subject: [PATCH 1/2] Compound operator expressions I don't actually know if the syntactic sugar is correct, so hopefully the lang team can sign off that it is in-deed correct. I also don't know if I can link to the test files without linking to Github, so I'm linking to Github. We could probably make linkcheck work for these eventually, if needed? --- src/expressions/operator-expr.md | 96 ++++++++++++++++++++++++-------- 1 file changed, 73 insertions(+), 23 deletions(-) diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index 7afe96d2e..80444715c 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -202,18 +202,18 @@ types. Remember that signed integers are always represented using two's complement. The operands of all of these operators are evaluated in [value expression context][value expression] so are moved or copied. -| Symbol | Integer | `bool` | Floating Point | Overloading Trait | -|--------|-------------------------|-------------|----------------|--------------------| -| `+` | Addition | | Addition | `std::ops::Add` | -| `-` | Subtraction | | Subtraction | `std::ops::Sub` | -| `*` | Multiplication | | Multiplication | `std::ops::Mul` | -| `/` | Division* | | Division | `std::ops::Div` | -| `%` | Remainder | | Remainder | `std::ops::Rem` | -| `&` | Bitwise AND | Logical AND | | `std::ops::BitAnd` | -| | | Bitwise OR | Logical OR | | `std::ops::BitOr` | -| `^` | Bitwise XOR | Logical XOR | | `std::ops::BitXor` | -| `<<` | Left Shift | | | `std::ops::Shl` | -| `>>` | Right Shift** | | | `std::ops::Shr` | +| Symbol | Integer | `bool` | Floating Point | Overloading Trait | Overloading Compound Assignment Trait | +|--------|-------------------------|-------------|----------------|--------------------| ------------------------------------- | +| `+` | Addition | | Addition | `std::ops::Add` | `std::ops::AddAssign` | +| `-` | Subtraction | | Subtraction | `std::ops::Sub` | `std::ops::SubAssign` | +| `*` | Multiplication | | Multiplication | `std::ops::Mul` | `std::ops::MulAssign` | +| `/` | Division* | | Division | `std::ops::Div` | `std::ops::DivAssign` | +| `%` | Remainder | | Remainder | `std::ops::Rem` | `std::ops::RemAssign` | +| `&` | Bitwise AND | Logical AND | | `std::ops::BitAnd` | `std::ops::BitAndAssign` | +| | | Bitwise OR | Logical OR | | `std::ops::BitOr` | `std::ops::BitOrAssign` | +| `^` | Bitwise XOR | Logical XOR | | `std::ops::BitXor` | `std::ops::BitXorAssign` | +| `<<` | Left Shift | | | `std::ops::Shl` | `std::ops::ShlAssign` | +| `>>` | Right Shift** | | | `std::ops::Shr` | `std::ops::ShrAssign` | \* Integer division rounds towards zero. @@ -441,24 +441,74 @@ x = y; >    | [_Expression_] `<<=` [_Expression_]\ >    | [_Expression_] `>>=` [_Expression_] -The `+`, `-`, `*`, `/`, `%`, `&`, `|`, `^`, `<<`, and `>>` operators may be -composed with the `=` operator. The expression `place_exp OP= value` is -equivalent to `place_expr = place_expr OP val`. For example, `x = x + 1` may be -written as `x += 1`. Any such expression always has the [`unit` type]. -These operators can all be overloaded using the trait with the same name as for -the normal operation followed by 'Assign', for example, `std::ops::AddAssign` -is used to overload `+=`. As with `=`, `place_expr` must be a [place -expression]. +*Compound assignment expressions* combine arithmetic and logical binary +operators with assignment expressions. + +For example: + +```rust +let mut x = 5; +x += 1; +assert!(x == 6); +``` + +The syntax of compound assignment is a [mutable] [place expression], the +*assigned operand*, then one of the operators followed by an `=` as a single +token (no whitespace), and then a [value expression], the *modifying operand*. + +Unlike other place operands, the assigned place operand must be a place +expression. Attempting to use a value expression is a compiler error rather +than promoting it to a temporary. + +Evaluation of compound assignment expressions depends on the types of the +operators. + +If both types are primitives, then the modifying operand will be evaluated +first followed by the assigned operand. It will then set the value of the +assigned operand's place to the value of performing the operation of the +operator with the values of the assigned operand and modifying operand. + +> **Note**: This is different than other expressions in that the right operand +> is evaluated before the left one. + +Otherwise, this expression is syntactic sugar for calling the function of the +overloading compound assigment trait of the operator (see the table earlier in +this chapter). A mutable borrow of the assigned operand is automatically taken. + +For example, the following expression statements in `example` are equivalent: ```rust -let mut x = 10; -x += 4; -assert_eq!(x, 14); +# struct Addable; +# use std::ops::AddAssign; + +impl AddAssign for Addable { + /* */ +# fn add_assign(&mut self, other: Addable) {} +} + +fn example() { +# let (mut a1, a2) = (Addable, Addable); + a1 += a2; + +# let (mut a1, a2) = (Addable, Addable); + AddAssign::add_assign(&mut a1, a2); +} ``` +
+ +Warning: The evaluation order of operands swaps depending on the types of the +operands. Try not to write code that depends on the evaluation order of operands +in compound assignment expressions. See [this test] for an example of using this +dependency. + +
+ +[mutable]: ../expressions.md#mutability [place expression]: ../expressions.md#place-expressions-and-value-expressions [value expression]: ../expressions.md#place-expressions-and-value-expressions [temporary value]: ../expressions.md#temporaries +[this test]: https://github.com/rust-lang/rust/blob/master/src/test/ui/expr/compound-assignment/eval-order.rs [float-float]: https://github.com/rust-lang/rust/issues/15536 [`unit` type]: ../types/tuple.md [Function pointer]: ../types/function-pointer.md From 61d063fc68d43f43edd0e9fb5c7de5bc3e072c88 Mon Sep 17 00:00:00 2001 From: "Havvy (Ryan Scheel)" Date: Wed, 13 Jan 2021 21:39:53 -0800 Subject: [PATCH 2/2] Address review request --- src/expressions/operator-expr.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index 80444715c..6b0fdc13e 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -498,8 +498,10 @@ fn example() {
Warning: The evaluation order of operands swaps depending on the types of the -operands. Try not to write code that depends on the evaluation order of operands -in compound assignment expressions. See [this test] for an example of using this +operands: with primitive types the right-hand side will get evaluated first, +while with non-primitive types the left-hand side will get evaluated first. +Try not to write code that depends on the evaluation order of operands in +compound assignment expressions. See [this test] for an example of using this dependency.