Hacker Read top | best | new | newcomments | leaders | about | bookmarklet login

In rust, assignment isn't an expression, but everything else is.


sort by: page size:

Nitpicking: assignment is an expression that returns () in Rust, meaning `foo(a = 1, a)` is valid if foo has a signature like `fn foo(x: (), y: i32)`. However, arguments are (mostly) defined to be evaluated from left to right.

On the other hand you can assign within expressions in Rust, and it's generally not been an issue that I've seen anyone complain about. However, that might be because the type checker usually catches you if you're making a mistake; assignment/variable binding return the type `()`, which doesn't work inside ifs or whiles

assignment being an expression is not a dangerous misfeature; what the assignment expression evaluates to is important to consider(see ocaml/rust).

You are mistaken about rust. I can't think of a construct that is not an expression.

Rust also has (almost) everything being an expression - things like this aren't uncommon:

    let x = if something {
        foo()
    } else {
        bar()
    }
Things which don't have a logical value evaluate to `()` (the empty tuple), I believe.

Specifically, note that mistaken use of `=` vs. `==` is impossible in Rust regardless of this proposal, since:

1. assignment is an expression that returns nil

2. `if` expressions require their conditions to evaluate to boolean

3. no types can be implicitly coerced to boolean

An example:

  fn main() {
      let mut x = 2;
      if x = 4 {}  // error: mismatched types: expected `bool` but found `()`
  }

Sorry, you are correct. I was thinking of situations like this:

  fn assign(a: &mut Bar, b: &Bar) {
    a.foo = b.foo;
  }
    
    assign(&mut a[0], &a[1]);
Bit contrived - next time Rust stops me doing something simple I will note it down!

Again to be clear, I'm not saying that there's anything wrong with Rust here.


Since you're using Rust as an example there, worth noting that unlike in C the assignment operator in Rust does not evaluate to the assigned value (it evaluates to the unit value `()` instead). In combination with the fact that `if` expressions in Rust require their conditions to be bools (the language has no automatic coercion to bool), this means that `if foo = 0` is guaranteed to be a type error.

(This difference in the behavior of the assignment operator is a result of Rust's ownership semantics; since assignment transfers ownership, having the assignment operator evaluate to the assigned value would actually result in the original assignment being entirely undone!)


It's not a corner case if you do it right.

For example, in C the assignment operator evaluates to the value of the right-hand side expression (so `int x = (y = 2);` initializes `x` to 2). But in Rust, the assignment operator always evaluates to `()` (a.k.a. "unit", the empty tuple), and trust me, this is how you want the language to work in the presence of pervasive move semantics and single ownership. Furthermore, nothing in Rust is "truthy": if-expressions accept a boolean and nothing else (this is also, IMO, exactly what you want in every language, but I'm sure others will disagree :P ). So `if x = 2 {` is a compiler error in Rust because `()` can't be coerced to a boolean (to say nothing of the fact that this reassignment would probably be a compiler error anyway because most variables in Rust are immutable). This doesn't require any acrobatics, it's just the natural fallout of how the rest of the language works.


This mistake also requires that the assignment operator has a result (and further, that the result can be silently coerced into a boolean for whatever reason)

In both Rust and Swift, this mistake doesn't compile, their assignment operators don't have a result and so it can't very well be true (or false) ‡

‡ Technically the result of Rust's assignment operators is the empty tuple, which is the closest to "doesn't have a result" in the type system. I don't know about Swift.


Rust uses the semicolon to distinguish between statements and expressions.

Rust doesn't do any special insertion/deletion, but take an expression and add a ; and it becomes a statement.

Yeah, let's compare with a stricter language:

In Rust, x = y evaluates to (), not any of the values in x or y.

In Rust, numbers are not implicitly usable as booleans in conditionals.


It's one of the things I love the most in Rust, and was previously just seen in functional languages.

Even scripting languages like Python feel clunkier than Rust due to the unnecessary statement/expression distinction.


Rust syntax really is crazy. It's designed to be utterly incomprehensible.

> Can't you just do

That's a declaration not an assignment, TFA is (somewhat oddly) using the language precisely and fittingly: https://doc.rust-lang.org/reference/expressions.html#assignm...

And there are cases where shadowing is not acceptable e.g. when updating bindings within a loop, you usually want to see the updates from outside the loop.


Not to mention that Rust uses = and == the same way as C, although the expression "a = b" has unit type.

Expressions in Rust are eagerly evaluated, but you can write lazily evaluated things without issue.

It does, in fact the article you posted, shows you exactly when rust allows assignment in conditionals.

As long as you're initializing a variable, it's allowed, if you're not initializing you'll have to use a block expression.

next

Legal | privacy