The idea of shortening let mut
to var
has been discussed many times before, and the general consensus always ends up being that it is not a good idea. I would like to propose something a bit different, so please hear me out.
I propose that instead of aliasing var
to let mut
, we instead just make mut
expand into let mut
when in the context of a variable declaration. For example:
let mut foo = 12;
// is identical to
mut foo = 12;
This solves the problems (readability, more concise) that people have with let mut
, whilst not causing the issues that people have (pattern matching and consistancy).
The most common issue people have with aliasing var
to let mut
is that it doesn't fit well with patterns, like let (x, mut y) = ...
. However, mut
gets rid of this problem, because you wouldn't write let mut (x, mut y)
if you were trying to pattern match, so why would someone want to write mut (x, mut y)
? You wouldn't do that, and it wouldn't compile.
This would be optional, of course. let mut x = 1
would still work fine, and people would just have to option of removing the let
to let it be implied.
There are a lot of other abbreviations used in rust (fn
, mod
, pub
) that all serve the purpose of writing less. It just doesn't feel right that one of the most commonly used keywords is so long.
:heart::crab:
Rust wants to make to make you think when you try and use mutation, even if only a little bit, because mutation can be difficult to reason about. Shortening let mut
to mut
doesn't fit this philosophy. Also, this makes mutation just as easy as no mutation. This will lead people to choose mutation because it will give them less compiler errors in the short term, and in doing so open themselves up to some weird bugs that could have been prevented with the syntactic salt that is let mut
.
tldr: var
wasn't rejected because of the name var
, but because it allowed easy mutation, which runs counter to Rust's philosophy.
This will lead people to choose mutation because it will give them less compiler errors in the short term, and in doing so open themselves up to some weird bugs that could have been prevented with the syntactic salt that is
let mut
.
I politely disagree. In fact, it is actually the other way around. Using mut
unnecessarily will cause compiler warnings, discouraging the use of unneeded mutability. The compiler doesn't warn when the use of mut
is actually needed.
I politely disagree. In fact, it is actually the other way around. Using mut unnecessarily will cause compiler warnings
The fact that people will choose mut
in the face of compiler warnings has been shown in practice, across many projects. Also, the problem isn't that people may choose to put mut
just for the heck of it, but that they will unintentionally mutate something that was supposed to be immutable. And because it is being mutated, there is no warning, and they used mut
because it is their default, it is their default because it gets rid of compiler errors that say they were trying to mutate things that are immutable even though they weren't supposed to mutate them in the first place. They will use mut
because it is just as easy as making it immutable. So the problem is a bit more subtle than you seem to think.
This solves the problems (readability, more concise) that people have with
let mut
Incorrect. Extreme brevity harms readability. See Perl. lol
Readers would ignore the let
vs mut
distinction far more often that let
vs let mut
, partially due to length difference, but let mut
works even better than say mutable
.
It's true boilerplate often harms readability, but boilerplate requires some complexity be repeated, not merely the let
in let mut
.
It harms readability even further if mut
also works for let mut
, especially when you consider code readers need not actually know Rust.
Rust syntax was designed largely to reduce cognitive load, not to reduce typing.
We use return
, continue
, and default
, not any shorter alternatives. And delegation RFCs have kinda given up the short syntaxes. I think Rust's omission of then
is now considered a mistake, but presumably helps C programmers.
Rust has short keywords only really for fundamental "items" used repeatedly by basically every module. It's similar cognitive load if you write fn
, func
, or function
, but actually just writing the shorter bare f(..) { .. }
increases cognitive load. I think var
invokes the minor linguistic subtlety that variable means mutable binding, while let
acts like a common term for binding, which makes let mut
very slightly clearer.
whilst not causing the issues that people have (pattern matching and consistancy)
The mut
statement would be orthogonal to the current language in some sense though. let mut foo
is not a special syntax, but is composed of let
statement + mut foo
pattern. It is in line with other places expects a pattern, where you can write match _ { mut x => ... }
, for mut x in
, or fn foobar(mut x: i32)
.
It seems unlikely to me that we would support mut $ident = $expr;
as a short-hand. I'm personally opposed to it both because it adds unnecessary compiler complexity, stylistic schisms, and for the reasons outlined by @KrishnaSannasi.
However, I've taken the liberty of reusing this issue towards improved diagnostics:
1.
mut x = 0;
--- help: missing `let`
The idea here is to check self.token.is_keyword(kw::Mut) && self.look_ahead(1, |t| t.is_ident())
.
2.
var x = 0;
--- help: to introduce a variable, write `let` instead of `var`
auto x = 0;
---- help: to introduce a variable, write `let` instead of `auto`
The idea here is to check:
is_ident_var_or_auto && !self.look_ahead(1, |t| is_brace(t))`
The relevant code is here: https://github.com/rust-lang/rust/blob/ece4977138a8eda96c234982e482fb43f67f1bee/src/libsyntax/parse/parser/stmt.rs#L44-L49
cc @estebank
@rustbot claim
Error: Parsing assign command in comment failed: ...tbot claim|error: expected end of command at >| :)...
Please let @rust-lang/release
know if you're having trouble with this bot.
@Centril Although I would also guess that the initial idea is very unlikely to end up accepted, it feels premature to unilaterally hijack the thread in your very first comment and make it have a different (and in a way opposite) purpose. Teams of the Rust project are designed to make decisions collectively. Improving diagnostics sounds good, but issue numbers are cheap.
@Centril Although I would also guess that the initial idea is very unlikely to end up accepted, it feels premature to unilaterally hijack the thread in your very first comment and make it have a different (and in a way opposite) purpose.
Implementing something as a diagnostic actually brings you closer to a working implementation -- I think more proposals should start out as diagnostics.
Teams of the Rust project are designed to make decisions collectively. [...]
I will not bother the other language team members with not-fully-formed proposals that we will not accept in either case. I converted the issue into the most actionable and productive thing it could be.
The place for ephemeral discussions is either on Discord or on internals.
If you want to discuss this further, I'm available at Discord (but will not respond to it further here).
[...], but issue numbers are cheap.
...but wasting everyone's time with things that will go nowhere (because it won't be accepted and because it is not important enough to be raised at the team) is not.
IMHO, the original thing this issue was opened for should be an RFC, not an issue. I'd have closed this, pointed the OP to the RFCs repo, and opened a new issue for the diagnostic issue.
This issue was literally in the RFCs repo initially, @Centril transferred it from there.
Incorrect. Extreme brevity harms readability. See Perl. lol
@burdges Language bashing is not welcome here
@steveklabnik Wait, so should I unassign here, and assign to the new issue?
@chocol4te Nah, just use this one.
Yeah, thats fine. You can just change this issue to be for diagnostics instead.
I'm sorry, I've been pretty busy with coursework, and I'm still fighting my Python installation to even build the compiler, let alone make progress on this. Sorry :(
I'll assign this to myself to work on when I have time. If you want to work on it however, feel free to work-steal it from me!
I would like to help with this
@JesterOrNot Sorry; should have updated this issue...! There's a PR https://github.com/rust-lang/rust/pull/65811 at the moment. Feel free to leave suggestions on it if you like. :)
Most helpful comment
It seems unlikely to me that we would support
mut $ident = $expr;
as a short-hand. I'm personally opposed to it both because it adds unnecessary compiler complexity, stylistic schisms, and for the reasons outlined by @KrishnaSannasi.However, I've taken the liberty of reusing this issue towards improved diagnostics:
1.
The idea here is to check
self.token.is_keyword(kw::Mut) && self.look_ahead(1, |t| t.is_ident())
.2.
The idea here is to check:
The relevant code is here: https://github.com/rust-lang/rust/blob/ece4977138a8eda96c234982e482fb43f67f1bee/src/libsyntax/parse/parser/stmt.rs#L44-L49
cc @estebank