cognitive-engineering-lab / aquascope

Interactive visualizations of Rust at compile-time and run-time
https://cognitive-engineering-lab.github.io/aquascope/
MIT License
2k stars 46 forks source link

Eager loss of read permission - wrong or just confusing? #93

Closed ethanbb closed 1 year ago

ethanbb commented 1 year ago

Hi, I'm still learning Rust so this may be a misunderstanding. I was looking at this example from chapter 4.5:

fn main() {
    let mut s = String::from("Hello");
    let s_ref = &s;   // 1
    println!("{s_ref}");
}

At point 1, Aquascope shows that s loses the R permission along with W and O - despite s_ref being an immutable reference, which seems wrong. However, if s is later used, this does not happen, e.g.:

fn main() {
    let mut s = String::from("Hello");
    let s_ref = &s;   // 1
    println!("{s_ref}");
    println!("{s}");
}

Here, s only loses W and O permissions at point 1. Is this wrong or just a somewhat confusing implementation detail?

willcrichton commented 1 year ago

This is a confusing implementation detail, see the discussion in cognitive-engineering-lab/aquascope#85. We're brainstorming some better ways to communicate what's happening.

ethanbb commented 1 year ago

Ah OK! Sorry for the duplicate. I have a follow-up though (sorry if this doesn't belong in an issue):

Say there's another line of code that doesn't use s or s_ref after println!("{s_ref}"); in example 1. Then s_ref dies after line 4 and loses all permissions. At this point (according to Aquascope) no path has an O permission. But according to the book, the O permission means that "data can be moved or dropped." If no path owns the data in s at the end of the frame, how could s ever be dropped?

gavinleroy commented 1 year ago

Great question, the permissions are associated with a specific path, and as you point out, O permission means "data can be moved or dropped". If no visible path has the O permission, then where did it go?! The short answer is that the compiler now owns this data and can issue an implicit drop on the memory when it chooses. This happens because s is no longer live (i.e., it's not used anymore) but the data still exists. We can simulate the compiler by inserting the call to drop ourselves:

Screenshot 2023-07-13 at 12 39 22

Inserting drops manually takes us back to C, where the programmer needs to know when to free memory. The power of ownership is that the compiler knows precisely when it can take over and issue these drops for us. As Will pointed out, liveness is an interesting problem for the visualization whose solution we're still trying to find.

ethanbb commented 1 year ago

Ah got it, thanks for clarifying!