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

Closures-Capturing 9.2.1 sample code needs update for rust 2018 #1169

Closed
1414C opened this issue Mar 30, 2019 · 0 comments
Closed

Closures-Capturing 9.2.1 sample code needs update for rust 2018 #1169

1414C opened this issue Mar 30, 2019 · 0 comments

Comments

@1414C
Copy link

1414C commented Mar 30, 2019

While working through Chapter 9 -> 9.2 Closures -> 9.2.1 Capturing I found that execution of the following code snippet resulted in an error (as expected) when executed in the embedded playground:

    let mut count = 0;

    // A closure to increment `count` could take either `&mut count`
    // or `count` but `&mut count` is less restrictive so it takes
    // that. Immediately borrows `count`.
    //
    // A `mut` is required on `inc` because a `&mut` is stored inside.
    // Thus, calling the closure mutates the closure which requires
    // a `mut`.
    let mut inc = || {
        count += 1;
        println!("`count`: {}", count);
    };

    // Call the closure.
    inc();
    inc();

    // expect a borrow failure here
    let _reborrow = &mut count;
    // ^ TODO: try uncommenting this line.

As expected, uncommenting the let _reborrow ... line resulted in an error:

   Compiling playground v0.0.1 (/playground)
error[E0499]: cannot borrow `count` as mutable more than once at a time
  --> src/main.rs:35:26
   |
26 |     let mut inc = || {
   |                   -- first mutable borrow occurs here
27 |         count += 1;
   |         ----- previous borrow occurs due to use of `count` in closure
...
35 |     let _reborrow = &mut count;
   |                          ^^^^^ second mutable borrow occurs here
...
54 | }
   | - first borrow ends here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0499`.
error: Could not compile `playground`.

To learn more, run the command again with --verbose.

Executing the same code on my workstation did not result in an error and a cargo check of the code returned a clean result:

cargo check
    Checking closures v0.1.0 (/<my_path>/rust_by_example/closures)
    Finished dev [unoptimized + debuginfo] target(s) in 0.23s

I am running the following build: stable-x86_64-apple-darwin unchanged - rustc 1.33.0 (2aa4c46cf 2019-02-28). / rust 2018

Presumably some changes have been made to rustc v1.33 / 2018 whereby it recognizes that closure variable inc is not referenced again in the code following the two inc(); calls? I am pretty new to Rust, by I think that the compiler is smart enough to recognize that the new assignment to _reborrowed is safe in this situation?

I updated the code snippet on my workstation as shown below, and found that the complier generated an error (as expected):

    let mut count = 0; // i32

    // a closure to increment `count` could take `&mut count` or
    // `count` but `&mut count` is less restrictive, so it takes
    // that(?).  `count` is immediately borrowed.
    // `mut` is required on `inc` because a `&mut` is stored inside.
    // callint the closure mutates the closure which in-turn requires
    // a `mut`.
    let mut inc = || {
        // count: &mut i32
        count += 1;
        println!("`count`: {}", count);
    };

    // Call the closure.
    inc();
    let _reborrow = &mut count;  // new location!
    inc();

Error message:

error[E0499]: cannot borrow `count` as mutable more than once at a time
  --> src/main.rs:48:21
   |
40 |     let mut inc = || {
   |                   -- first mutable borrow occurs here
41 |         // count: &mut i32
42 |         count += 1;
   |         ----- first borrow occurs due to use of `count` in closure
...
48 |     let _reborrow = &mut count;
   |                     ^^^^^^^^^^ second mutable borrow occurs here
49 |     inc();
   |     --- first borrow later used here

error: aborting due to previous error

I am pretty sure that this is the scenario that the page author wanted to illustrate, as this is the behaviour exhibited by the embedded playground (and also with edition = "2015"). The concern is that the example as written illustrates the author's intent in the playground, but not in the current stable release (1.33)/2018 of the rust toolchain.

The code example should probably(?) be enhanced to illustrate / compensate for the effects described above. Maybe something like this:

    let mut count = 0;

    // A closure to increment `count` could take either `&mut count`
    // or `count` but `&mut count` is less restrictive so it takes
    // that. Immediately borrows `count`.
    //
    // A `mut` is required on `inc` because a `&mut` is stored inside.
    // Thus, calling the closure mutates the closure which requires
    // a `mut`.
    let mut inc = || {
        count += 1;
        println!("`count`: {}", count);
    };

    // Call the closure.
    inc();
    // let _reborrow = &mut count;     // error[E0499]: ...
    // ^ TODO: try uncommenting this line.
    inc();

    // let _reborrow = &mut count;  // okay!
    // ^ TODO: try uncommenting this line.

Thanks for looking (and also for putting together such a great book).

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

No branches or pull requests

2 participants