If I'm understanding correct, the major change here for Rust users (rather than people who hack on the compiler) is that mutable references will not be considered to be "interfering" with other references being made at the same time until they're actually written to for the first time. This makes intuitive sense to me, but I suspect that there may be a bit of concern that this will make things more confusing when reading code and trying to understand what's going on. I'd be lying if I said that thought didn't occur to me, but at this point being surprised at how much I end up liking the way things turned out has become the norm for me; I remember having misgivings about nested import paths (rather than only being able to use `{`...`}` at the very end), match ergonomics, and `.await` as a postfix keyword but pretty quickly became glad they decided things the way they did after using each of them a bit when they finally got stabilized. I think I did realize that I'd like NLL (i.e. the borrow checker detecting the final use of a reference and not considering it as conflicting for the remainder of the scope) before it landed, but I know a lot of people had misgivings about that as well. I imagine this will be one of those things that in a few years will seem weird it wasn't always how it worked!
> ...by the time x.len() gets executed, arg0 already exists...<p>So, I realize that this is the way that Java does it--and, presumably, one still doesn't get fired for doing whatever Java does ;P--but, would it not actually make more sense for the arguments to be evaluated before the target reference, making the argument order more like Haskell/Erlang (but very sadly not Elixir, which makes it awkwardly incompatible with Erlang and breaks some of the basic stuff like fold/reduce)? Particularly so, given that, as far as I can tell from this example, what makes arg0 have the type that it does is the type of the function that hasn't even been called yet? (As in, the semantic gap I am seeing between what the user probably meant and what the compiler wants to do is that "x" shouldn't really be mutably-borrowed until the call happens, and the call here clearly shouldn't happen until after the arguments are evaluated.) (Note: I do not program in Rust currently; I just have spent a number of decades analyzing languages and at times teaching college language design courses. I might be missing something obvious elsewhere that forces Rust to do this, but that one example, in isolation, at least feels like an unforced error.)
I have not programmed Rust, yet. But this article gives me a feeling that this looks similar to database transactions. This might be wildly wrong but for me I see an analogy:<p>Once you get the &mut reference, you have your tree, which then looks to me like you have created a transaction. An in this transaction context you do your things.
<p><pre><code> fn two_phase(mut x: Vec<usize>) {
let arg0 = &mut x;
let arg1 = Vec::len(&x);
Vec::push(arg0, arg1);
}
</code></pre>
> This code clearly violates the regular borrow checking rules since x is mutably borrowed to arg0 when we call x.len()! And yet, the compiler will accept this code<p>Does anybody else wish the compiler wouldn't and would be even more verbose? I know one of the biggest learning curves (personally) for Rust is the borrow checker complaining hardcore and "getting in your way" preventing you from basically doing anything you're used to (passing around pointers in C or objects in JavaScript (even though you should be following immutable practices and not doing object mutation... most of the time))<p>I'm sure there's probably been discussions on how to make the borrow checker less "mean/rigid/obtuse" but silently passing something as "non mut" and it actually does "mut" stuff, I wouldn't have guessed Rust allowed that.<p>Edit: gah, I did not realize the function signature is (mut x), I thought it was just (x) and the mut was implied which is what I was trying to call out, apologies.