News for hackers. Stuff that matters.
Re:Dave Herman’s contributions to Rust by melling on Monday May 03, 2021 @05:12AM (#27023007)
Haven’t learned Rust yet. I see they debated this:

   let and let mut
   let and var
And went with the verbose option.

Swift went with the succinct option, which I love about the language. In practice I suppose I do mostly type “let” in Swift so it doesn’t matter much

Swift, however, chose ‘func’ instead of ‘fn’, after much debate.

Those little things that are debated initially, then forever

Re:Dave Herman’s contributions to Rust by Thiez on Monday May 03, 2021 @06:22AM (#27023361)
In Rust the `mut` does not apply to the `let`, but to the variable binding. So you can do this:

    let (x, mut y) = (5, 10);
After this statement `x` will not be mutable, but `y` will be. You cannot do

    let mut (x, y) = (5, 10);
So the way Rust currently works just doesn't map clearly on `let` and `var`.
Re:Dave Herman’s contributions to Rust by Macha on Monday May 03, 2021 @07:02AM (#27023587)
This is true, but the decision was made far back enough that other design decisions would have been weighed with consistency with the short behaviour in mind had that been the option chosen, and Rust would work slightly differently than how it currently works.

This is in the era of a new version having patch notes like (paraphrased) "Of the four pointer types with special syntax, we've converted two of them to regular types with names and deleted the fourth" - it predated that much concern with backwards compatibility.

Re:Dave Herman’s contributions to Rust by chrismorgan on Monday May 03, 2021 @06:52AM (#27023516)
A relevant period of history here is the mutpocalypse, where the question was raised “why are we calling this &mut and teaching it as being about mutability when what we actually care about (for memory safety) is uniqueness and aliasing?” Had that side prevailed, &mut would have been renamed (the main candidates presented were &uniq and &only), and all bindings would have become mutable (`let mut` would have disappeared), because that concept wouldn’t make a great deal of sense any more. These are the only technical changes that it would have entailed (the biggest change would have been in pedagogy).

In the end, social factors and inertia trumped technical precision and consistency. I am strongly inclined to think this was a mistake. Mutability is easier to explain initially, but teaches an incorrect mental model that hinders a correct understanding of Rust’s approach to memory safety, falling apart as soon as you touch things like atomics, RefCell or Mutex, which mutate self despite taking it as &self, a supposedly immutable reference.

Re:Dave Herman’s contributions to Rust by NanoCoaster on Monday May 03, 2021 @07:18AM (#27023676)
> Mutability is easier to explain initially, but teaches an incorrect mental model that hinders a correct understanding of Rust’s approach to memory safety, falling apart as soon as you touch things like atomics, RefCell or Mutex.

Could you elaborate or link to some material / discussion regarding that? I'd be very interested in how the alternative approach you're describing would change (or make unnecessary) constructs like RefCell.

Re:Dave Herman’s contributions to Rust by chrismorgan on Monday May 03, 2021 @07:44AM (#27023858)
The changes I described for the mutpocalypse vision are basically all there is to it, because &mut has always been a misnomer, never about being a mutable reference as its name replies, but rather about being a unique reference, that nothing else holds a reference while you have that one. The main thing the mutpocalypse sought to achieve was to adjust Rust’s syntax to match its semantics (including to remove mutability tracking on bindings, because that wasn’t part of Rust’s necessary semantics, and wouldn’t make as much sense after the trivial syntax change).

The thing I’m noting about atomics, RefCell and Mutex is how they have methods that (safely) mutate themselves, despite taking &self, a supposedly immutable reference.

(I’ve modified the final sentence in my original comment to clarify this.)

Re:Dave Herman’s contributions to Rust by NanoCoaster on Monday May 03, 2021 @07:56AM (#27023932)
I see, interesting point. Thank you :)
Re:Dave Herman’s contributions to Rust by chrismorgan on Monday May 03, 2021 @08:02AM (#27023983)
I feel like making one more note. I said that “mutable references” was a misnomer and that it’s actually about unique references, but even that’s a bit of a misnomer, because it’s not quite about uniqueness, but uniqueness of access. You can have multiple &mut borrows to the same thing, but only one of them is accessible at any given time:

  let mut x = 1;
  let y = &mut x;
  let z = &mut *y;
  *z += 1;
  *y += 1;
  assert_eq!(x, 3);
z and y both point to x, but only one is accessible at any point in time. Touching y finishes the z borrow; if you swapped the increment lines, it wouldn’t compile.

My memory is fuzzy (this was quite some years back), but I have a vague feeling that this lack of precision in the use of the word “unique” was a factor in some baulking at the proposed change. (“You’re trying to fix something that we admit is strictly wrong, but you’re not even making it right!”)

Re:Dave Herman’s contributions to Rust by xfer on Monday May 03, 2021 @09:29AM (#27024812)
Would this have worked pre-NLL?
Re:Dave Herman’s contributions to Rust by Thiez on Monday May 03, 2021 @09:46AM (#27025005)
The pre-NLL version would need some additional scopes. In some ways the current borrow-checker is a lot friendlier (there are also some things possible today that weren't before) but it was also a simpler time, where one could easily imagine the various lifetimes. Getting started with the language was harder, but I think internalizing the borrow-checker was easier, because the rules were simpler and you were forced to learn them for anything more complex than 'hello world'.

    let mut x = 1;
    {
        let y = &mut x;
        {
            let z = &mut *y;
            *z += 1;
        }
        *y += 1;
    }
    assert_eq!(x, 3);
Re:Dave Herman’s contributions to Rust by steveklabnik on Monday May 03, 2021 @10:29AM (#27025518)
> Getting started with the language was harder, but I think internalizing the borrow-checker was easier,

So here's a funny thing: depending on what you mean, I don't think this is actually true. Let me explain.

The shortest way of explaining lexical lifetimes vs NLL is "NLL is based on a control-flow graph, lexical lifetimes are based on lexical scope." CFGs feel more complex, and the implementation certainly is. So a lot of people position this as "NLL is harder to understand."

But that assumes programmers think in the simple way. I think one of Rust's under-appreciated contributions is that programmers intuitively understand control flow graphs better than we may think, and may not intuitively understand lexical scope. Sure, by some metric, NLL may be "more complex" but practically, people only report it being easier to learn and do what they would naturally expect.

Re:Dave Herman’s contributions to Rust by Thiez on Monday May 03, 2021 @11:00AM (#27025897)
Hey Steve :-) I've been following and using Rust since early 2013 (so starting around the same time you did, when I compare our contributions to the compiler) and back then I definitely did not find the lexical lifetimes hard to understand. I remember also noticing an increase in "dumb" lifetime-related questions after NLL landed, seemingly caused by a lack of understanding of how they work.

Perhaps it's all just confirmation bias on my end, but I think truly understanding lifetimes was easier the way I learned it back then. That said, I have never bothered to write documentation for the Rust project, whereas few Rust contributors can claim to be in the same league as you in that area. We probably have very different perspectives.

Re:Dave Herman’s contributions to Rust by steveklabnik on Monday May 03, 2021 @11:38AM (#27026448)
Oh totally, I know you :) It's interesting how our perceptions are different though, I think a lot of the "dumb" questions went away since NLL. I wonder if there's a way to quantify this.

So, I think this is the thing: I also think that it was easier to learn lexically, personally. I too was worried that it would make things harder. But, I just don't think that's been demonstrated to be true across most people. It is, however, only my gut-check feeling for what I've seen. I could be wrong.

(And, the borrowcheck documentation is very minimal, and didn't really change with NLL, other than needing to add some println!s to make things not compile again. So it's certainly not because I wrote some amazing docs and explained it in a good way, hehe.)

Re:Dave Herman’s contributions to Rust by chrismorgan on Monday May 03, 2021 @02:20PM (#27028751)
I started in mid-2013 too, and my position is similar to yours. I'd characterise it like this: lexical lifetimes are easier to grok, but NLL turns out to be more practical, doing what people actually want (where LL didn't) enough that it overcomes the greater conceptual complexity, because you have to actually think about the concepts less often.
Re:Dave Herman’s contributions to Rust by xfer on Monday May 03, 2021 @09:53AM (#27025088)
Yes, the pre-NLL version makes it clear to see why swapping the assignment lines wouldn't work.

EDIT: i think some tooling showing lifetimes for borrows would be very helpful. Can mir do this? I haven't tried it.

Re:Dave Herman’s contributions to Rust by est31 on Monday May 03, 2021 @07:45AM (#27023866)
> falling apart as soon as you touch things like atomics, RefCell or Mutex.

Does it really fall apart? None of these constructs change the fact that if a &mut T is available, you can call functions on that type that take &mut self. The only thing that breaks is the assumption that non-presence of mut implies that there is no way to call those &mut self functions. If you change it to "non-prsence of mut implies that you need extra constructs like atomics, RefCell or Mutexes in order to get mutable access" it works out again.

Re:Dave Herman’s contributions to Rust by chrismorgan on Monday May 03, 2021 @07:46AM (#27023876)
The mental model of & being immutable and &mut being mutable, that’s what falls apart. Here are types that are taking &, and yet are mutating themselves.

This becomes a huge deal when people think that they have an immutable data structure just because they have an & reference to it. Someone will inevitably stash a mutex or similar in there because they just need to be able to mutate it this once… I mean these three times… I mean all the time. Oh, you wanted this immutable data structure so you could diff it for your VDOM or incremental calculations or whatever? Heh, guess you’ll have to find some other way or structure things so that mutations can be propagated through the object tree or something. And you’ll keep on having cache issues from time to time when people forget to jump through the right hoops. Sorry about that.

So yeah, the mental model of &/&mut references being about mutability is just completely and harmfully wrong. Rust does not have a way of guaranteeing immutability.

Re:Dave Herman’s contributions to Rust by est31 on Monday May 03, 2021 @05:00PM (#27030575)
> The mental model of & being immutable and &mut being mutable, that’s what falls apart. Here are types that are taking &, and yet are mutating themselves.

&mut still implies mutability, and even the constructs like Mutex or RefCell still expose their mutability support via &mut references. Only atomics don't (they don't provide any &mut access). Note that you don't add const like in C/C++, you add &mut.

As for the VDOM caching thing, you have a point. But even if Rust had &uniq and &shared pointers, the challenge would be the same. Users might still use constructs like RefCell.

Re:Dave Herman’s contributions to Rust by chrismorgan on Tuesday May 04, 2021 @01:20AM (#27034293)
Mutex::lock() takes &self. RefCell::borrow_mut() takes &self. Those (and try_ variants) are the main ways people will use those types to gain access to their interior mutability.

Sure, both do have get_mut() which takes &mut self (though these came after 1.0), but that’s seldom how you’ll actually access it.

> But even if Rust had &uniq and &shared pointers, the challenge would be the same.

Remember again that the mutpocalypse wasn’t ever about changing the semantics, just about fixing incorrect labelling. I’m not saying the challenges would be different, just that &mut is false advertising, giving people the impression that & means an immutable reference, when it just doesn’t. &/&mut misleads people into thinking they can have immutable data structures, but you’d actually need an OIBIT (like Send) to achieve that.

Re:Dave Herman’s contributions to Rust by est31 on Wednesday May 05, 2021 @05:16PM (#27055939)
> Mutex::lock() takes &self. RefCell::borrow_mut() takes &self. Those (and try_ variants) are the main ways people will use those types to gain access to their interior mutability.

Yeah they take &self, but that wasn't my point. My point was what they expose, which is MutexGuard in the case of Mutex, and if you want to modify the interior, you'll likely use the DerefMut impl which returns a &mut T. Same goes for RefCell::borrow_mut().

My point was that you don't mutate a &self reference directly in these instances, but turn a &self reference into a &mut self reference and then mutate. Again, atomics are an exception.

> just that &mut is false advertising

it is not false advertising, it implies mutable access. Had Rust been mut by default and had &T been &const T instead, I would agree with the false advertisement point. But thankfully it's non-mut by default.

Anyways, even if &mut were false advertising, and it were a bump in the learning curve, note that &uniq is such a bump too, because you have no idea what it says or implies initially. &mut makes it clear that if you want to mutate, you'll likely need a &mut somewher. But &uniq does not make this obvious, so you are required to learn something early on in Rust's comprehension, while &mut requires you to learn something later on. Generally, Rust has been criticized for having a steep learning curve at the start. In general I think it's worth it to learn Rust, but this wouldn't make it any better but worse.

Re:Dave Herman’s contributions to Rust by chrismorgan on Friday May 07, 2021 @07:05AM (#27074574)
I steadfastly maintain what I’m saying.

RefCell allows you to get a mutable reference via an allegedly-immutable reference. That it goes via a guard type is quite immaterial. It breaks the model.

&mut implies & is immutable.

Rust is teaching an incorrect mental model, which I believe is the wrong mental model to teach. Sure, &uniq is not devoid of problems, because most of the time &mut will suggest the right thing for beginners. But the spelling &mut is categorically wrong at the fundamental technical level. It was never actually about mutability.

Re:Dave Herman’s contributions to Rust by jeltz on Monday May 03, 2021 @07:44AM (#27023850)
I agree with that thinking about it in terms of mutability is a bit missleading but I am not sure how your idea would fix the issues with RefCell and Mutex. Additionally I think that some code is clearer with enforced single assignment in the syntax.
Re:Dave Herman’s contributions to Rust by jerryluc on Monday May 03, 2021 @05:15AM (#27023021)
In rust it played out well due to the usage of mut in other places. As in:

  fn (&mut T)
Re:Dave Herman’s contributions to Rust by dom96 on Monday May 03, 2021 @05:35AM (#27023130)
Same for Nim which uses let and var:

    proc (x: var T)
Re:Dave Herman’s contributions to Rust by MrBuddyCasino on Monday May 03, 2021 @05:32AM (#27023111)
Kotlin's version is even better: val & var

Super clear. The "let" version smells a lot of "I have a CompSci PhD".

Re:Dave Herman’s contributions to Rust by wink on Monday May 03, 2021 @05:57AM (#27023240)
No, not at all. I hate var & val because I never can remember which is which (from Scala, which I never really used a lot).

let vs let mut is /clear/ - you can simply not mix them up.

Re:Dave Herman’s contributions to Rust by akvadrako on Monday May 03, 2021 @06:05AM (#27023273)
How is it not clear that var is variable?
Re:Dave Herman’s contributions to Rust by rover0 on Monday May 03, 2021 @10:08AM (#27025268)
I'm a javascript developer.

if mutable is expensive, and should be difficult then "let mut" makes more sense.

var looks like a default to me, not a special case that needs care.

Re:Dave Herman’s contributions to Rust by leshow on Monday May 03, 2021 @05:49PM (#27031190)
Nitpick: "expensive" may be the wrong word there, to me that implies some kind of runtime cost. The stated reason for the keyword is that it forces users to think a little bit more about mutability. You may want do this because safe mutability requires exclusive ownership.
Re:Dave Herman’s contributions to Rust by mkl on Monday May 03, 2021 @06:29AM (#27023402)
Yes. I think the problem may be with the other one. "val" (and "let") don't seem obviously constant to me.
Re:Dave Herman’s contributions to Rust by MrBuddyCasino on Tuesday May 04, 2021 @08:33AM (#27036876)
var => variable

val => value => is immutable

Of course people are different, but this seems clear as day, assmuning very basic familiarity with functional programming?

Re:Dave Herman’s contributions to Rust by jeltz on Monday May 03, 2021 @07:35AM (#27023799)
Yes, whenever I get confused I recall that var is obviously variable so therefore the other one must be val.
Re:Dave Herman’s contributions to Rust by nicoburns on Monday May 03, 2021 @07:38AM (#27023818)
Let is definitely confusing given that JS has let and const (with let being mutable)
Re:Dave Herman’s contributions to Rust by wink on Monday May 03, 2021 @08:02AM (#27023977)
But that is cross-language, which is not ideal but not an internal problem if you work in one code base. (O)Caml also has `let` and is quite a bit older than JS.
Re:Dave Herman’s contributions to Rust by jodrellblank on Monday May 03, 2021 @04:25PM (#27030201)
C# uses “var” to mean “infer the type”, nothing to do with mutability or not.

“Let” feels like some in-joke, coming from a math via lisp heritage of “let k be any number...” to distinguish it in English from the surrounding writing. I have to guess that in early lisp (= k 5) would be an error as k isn’t defined and (k 5) errors because k isn’t a function and (let (k 5)) comes out of need for a binding function and why not “let”.

In c-like languages “k=5” is an established binding that both programmers and compilers can deal with. What does “let k=5;” add to Rust over “k=5;” ?

Re:Dave Herman’s contributions to Rust by rovolo on Monday May 03, 2021 @02:17PM (#27028708)
"val" is short for "value"
Re:Dave Herman’s contributions to Rust by melling on Monday May 03, 2021 @05:41AM (#27023157)
Practically, I prefer let and var because of autocompletion. Type one letter then tab. Of course, if I could dictate I might prefer something else.

I think of it as being more math like rather than PhD.

Nothing wrong with borrowing from math.

Re:Dave Herman’s contributions to Rust by rocqua on Monday May 03, 2021 @05:56AM (#27023232)
From the perspective of "language designers influencing programmers", the difficulty of auto-completing to `let mut` could be seen as something positive.
Re:Dave Herman’s contributions to Rust by BiteCode_dev on Monday May 03, 2021 @06:45AM (#27023487)
A good IDE will let you type "mu", and autocomplete with "let mu", cycling on tab will give you more options.
Re:Dave Herman’s contributions to Rust by mjw1007 on Monday May 03, 2021 @06:52AM (#27023523)
It's interesting if "let" nowadays has mostly 'academic' connotations.

30 years ago I think it would have reminded people more of BASIC or Fortran than (say) Scheme.

Re:Dave Herman’s contributions to Rust by Macha on Monday May 03, 2021 @07:07AM (#27023612)
I think this would have been more true 10 years ago when Haskell and Lisp were the most likely place for people to have encountered "let".

Now? It's in Javascript in its ES6 evolution and related languages, Swift, Rust, and probably other "newer" languages I'm not aware of. Scala had it ten years ago also, but is more mainstream than it was then.

Re:Dave Herman’s contributions to Rust by Ar-Curunir on Monday May 03, 2021 @12:12PM (#27026897)
The hamming distance between val and var is tiny; easy to miss in a code review.
Re:Dave Herman’s contributions to Rust by MrBuddyCasino on Tuesday May 04, 2021 @08:32AM (#27036864)
When assigning to val more than once: in a statically checked language the compiler will complain, and devs default to 'val' anyway. In a dynamic language you'd quickly get a runtime error.

Using 'var' instead of 'val' where possible: the compiler/linter will tell you this.

Or do you mean something else?

Re:Dave Herman’s contributions to Rust by pkfoo on Monday May 03, 2021 @06:53AM (#27023528)
It's bastardized OCaml. Instead of OCaml's mutable they inexplicably chose mut, which is ugly (same as pub).

But everyone is cheering them on.

Re:Dave Herman’s contributions to Rust by rtoway on Monday May 03, 2021 @07:00AM (#27023568)
I think their reasoning for things that are shortened is that if it's something you will be writing a lot, it's nicer to have it shortened. So pub fn mut etc. are shortened, but return isn't