Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Proposal] Prevent compilation of assignment of assignment #1227

Closed
KalitaAlexey opened this issue Jul 28, 2015 · 10 comments
Closed

[Proposal] Prevent compilation of assignment of assignment #1227

KalitaAlexey opened this issue Jul 28, 2015 · 10 comments

Comments

@KalitaAlexey
Copy link

let mut x = 5
let y = (x = 6)

Now compiles, but it is should not.

@nagisa
Copy link
Member

nagisa commented Jul 28, 2015

While the behaviour is indeed interesting (result of assignment expression is ()), I don’t think prevention is the way to go here. The reason is that we allow all kinds of expressions in many locations and forbidding this particular expression in this particular context would make the language inconsistent.

Perhaps a lint would be better; it looks somewhat footgunny because result of assignment expression in most other languages is the assigned value.

@KalitaAlexey
Copy link
Author

It may lead to some inadequate errors when working with generics

@withoutboats
Copy link
Contributor

A lint would be a good idea here; a hard error would introduce a weird inconsistency to Rust's semantics.

Possibly a special note could be appended if an assignment expression fails to typecheck (directly or as a variable created by a let expression), explaining that assignments evaluate to ().

@KalitaAlexey
Copy link
Author

Multiple assignments are unavailable in Rust, because only one variable must be an owner. So this code doesn't make a sense in any situation. Also this is error-prone. Why should this be allowed? Only to make Rust's semantics be consistent? It is weird. Rust aims to eliminate many errors. This is one of those errors.

@withoutboats
Copy link
Contributor

First of all, making this code not compile would be a backwards incompatible change, so that's really not an option. This is a perfectly valid way of assigning () to the variable y in Rust, even though that isn't what someone typing this probably wants (this is why warning the programmer is appropriate here).

An assignment is an expression that evaluates another expression and assigns its value to a variable declared by a let expression; the assignment expression evaluates to (). This definition of "assignment" necessarily means that you can assign an assignment expression to a variable.

The only way this would be possible would be to change the type of value an assignment evaluates to, and to change assignments to take any expression that does not evaluate to that type (similar to the way that if takes any expression that evaluates to bool). The bottom type (!) could be used for this, for example.

However, again, this change is not backward compatible. Adding a warning is.

@KalitaAlexey
Copy link
Author

@withoutboats I am not sure code contains this exists. And also if that code is exists, doesn't this mean that code contains an error?
Is it very hard to implement check for situation where right side of assignment is another assignmed enclosed in parantheses?

@withoutboats
Copy link
Contributor

@KalitaAlexey : first, the assignment doesn't need to be enclosed in parens. let y = let x = 0; and let x; let y = x = 0; are both valid Rust also.

The problem is that the only sensible way to differentiate between expressions during the static analysis phase of Rust is by the type of the expressions. Currently, assignments evaluate to (), it wouldn't be a very good idea to make it impossible to assign a variable to (). So what you'd need is for assignments to evaluate to a new type, and to change the semantics of assignments to not allow you to assign a variable to that type. This requires two pretty large changes to the semantics of the language which don't seem to be in the spirit of RFC #1122. The current semantics may be surprising, but they are not undefined behavior or underspecified.

So some sort of lint seems much more sensible here. It could identify any assignment of an assignment to issue a warning that assignments evaluate to ().


I do think that it would be better if assignments evaluated to ! and if ! could not be assigned to a variable, but I don't think either of these changes would be better enough to justify breaking backcompat.

@KalitaAlexey
Copy link
Author

@withoutboats Oh. I have figured out. I have though that Rust's analyzer can determine case where right-side of assignment is another assignment.

@gsingh93
Copy link

While I agree that if we were to do something like this it would fit better as a lint than as an error, I don't see how the lint would end up being helpful. I can't think of a non-trivial case where assigning the result of an assignment to a variable by accident would compile without either type checking errors or unused variable warnings. If you can think of convincing a non-trivial case however, then you can propose this functionality in rust-clippy.

@withoutboats
Copy link
Contributor

It's not so much that it would compile as that new users may be confused about why it does not compile, because they are used to languages with multiple assignment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants