Shouldn't NLL be able to figure this out?

So, I have this code in <edition = "2018">, which brings in NLL support, and so I presumed that code that used to look like this:

let app_ref = &mut self.app;
let ws_ref = &mut self.window_size;
self.gl.draw(render_args.viewport(), |c, gl| {
    //mutably and immutably use app_ref and ws_ref
});

to something that I thought that the compiler could manage...

self.gl.draw(render_args.viewport(), |c, gl| {
    //Use both here again
});

I presumed that the compiler could manage, because there were separate components of self being used, but this unfortunately ends up in a bit of a pickle...

error[E0501]: cannot borrow `self.gl` as mutable because previous closure requires unique access
error[E0500]: closure requires unique access to `self` but it is already borrowed

and upon further modification to appease the compiler, I end up at

error[E0502]: cannot borrow `self.gl` as mutable because it is also borrowed as immutable
error[E0502]: cannot borrow `self` as immutable because it is also borrowed as mutable

Great... it's misunderstood me for a troublemaker who would attempt to hold both a mutable reference and an immutable reference, and use them pfft. I mean, clearly it works in the first example, so why not in the second?

Finished dev [unoptimized + debuginfo] target(s) in 3.87s

(Output of compiling the first example)
Ps., for those of you wondering, I'm using piston.

I think this boils down to wanting precise closure borrows, as discussed here.

3 Likes

NLL is about adjusting (shrinking) lifetimes from the lexical scope of a variable to something less, in order to avoid errors where you want the lifetime to end before the variable technically goes out of scope. These are mostly the same class of errors that can be solved (in pre-NLL Rust) by introducing a new block scope (although some cannot).

Your case is not like that. There is no way to assign lifetimes to self and self.gl so that they do not overlap, and there's no way to limit which parts of self the closure borrows, so NLLs are not going to help.

1 Like

Ah, thanks for the insight, it seems that it is still necessary to use the code I mentioned in the original question. I guess I'll have to wait a bit more for this to be sorted out in Rust at some point. For now, it's actually okay, because I only have 2 mutable references I actually need to take as shown in my example.