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

Smart Pointer dereferencing rules #538

Closed
joliss opened this issue Mar 14, 2017 · 3 comments
Closed

Smart Pointer dereferencing rules #538

joliss opened this issue Mar 14, 2017 · 3 comments
Labels
Milestone

Comments

@joliss
Copy link
Contributor

joliss commented Mar 14, 2017

I'm reading the Smart Pointers chapter, and I found myself feeling confused about two things for quite a while:

  1. I was first left wondering why we can use a Box without dereferencing it in the Box chapter in println!("b = {}", b);. Then I thought that the automatic (de)referencing rules ("Where's the -> operator?", Chapter 5) might apply. Then I tried passing a Box<i64> into an i64 -> () function, which failed, so I finally concluded that we do need explicit dereferencing (*b), except that Box implements the Display trait so we can pass it directly into println!.

    So the problem I'm reporting here is that I ended up with the wrong intuition upon reading the examples. Perhaps being more explicit about what's going might help.

    Also, I wonder if it might be a good idea to link to the automatic (de)referencing rules somewhere in the Smart Pointers chapter as a reminder, because surely they are relevant here.

  2. The deref coercion rules at the bottom of the Deref chapter say:

    Rust does deref coercion when it finds types and trait implementations in three cases:

    • From &T to &U when T: Deref<Target=U>.
    • ...

    I was unclear how this rule would deref *my_favorite_song from Mp3 into a Vec, because my_favorite_song is of type Mp3 (T) and not &Mp3 (&T) -- literally until I wrote this issue, and then I realized that Rust probably automatically inserts an & to make it work, per the same automatic (de)referencing rule as above. This might be worth pointing out explicitly, if that's what's actually hapenning.

@steveklabnik
Copy link
Member

Thanks @joliss ! Both great points. We should explicitly cover both of these things, IMO.

@carols10cents carols10cents added this to the ch15 milestone Mar 15, 2017
@0xSiO
Copy link
Contributor

0xSiO commented Mar 25, 2017

In the section on interior mutability under the explanation for listing 15-15, it's mentioned that you can edit the value in an Rc<Refcell<i32>> by "dereferencing the Rc<T> and calling borrow_mut on the RefCell" which is a little misleading in the context of the code sample itself:

let value = Rc::new(RefCell::new(5));
// ...
*value.borrow_mut() += 10;

The explanation seems to overemphasize the precedence of the deref operator - rather, we're calling borrow_mut on the automatically dereferenced value pointer and then explicitly dereferencing the resulting RefMut:

// behind the scenes
*(*value).borrow_mut() += 10;

Just a small issue with semantics, but would fall under issue 1 of @joliss's post.

@carols10cents
Copy link
Member

carols10cents commented Sep 18, 2017

So @steveklabnik and I talked about this today, sorry this has taken us so long to get to!!

We made this clarification around this example involving dereferencing Rc and RefCell types, this was definitely wrong: 00438d0 In addition, we added a reference back to the auto dereferencing rules from chapter 5. Great suggestion!!

We decided the Mp3 example wasn't great, and that's completely gone. Instead, we're building up our own type that's like Box<T> in order to understand how it works. I hope it's better, and I'd love new issues on the new example if you have time to read it over! (Here's the diff, it's kind of terrible to read on github though, it should hopefully be up on the nightly book at https://doc.rust-lang.org/nightly/book/second-edition/index.html soon)

Regarding the first part:

Then I tried passing a Box into an i64 -> () function, which failed, so I finally concluded that we do need explicit dereferencing (*b)

Yes, we do need explicit dereferencing to get a T out of a Box<T>, your intuition is correct here! It's only when you want an &T and you have a &Box<T> that the deref coercions kick in.

except that Box implements the Display trait so we can pass it directly into println!.

Your intuition is also correct here-- the implementation of Display on Box is defined to display the value inside the box.

So the problem I'm reporting here is that I ended up with the wrong intuition upon reading the examples.

I'm not sure where your intuition is incorrect here!

As @steveklabnik and I were trying to figure out how to address this, we came to a conclusion that this is the interaction of a bunch of features (method auto dereferencing, deref coercions, smart pointers) and we've addressed each of these separately, but not this combination explicitly. There are a lot of features that we don't have the space to show how they interact exactly, but we do want to build up the readers' intuitions of the features in isolation so that using them together makes sense. We're just not sure exactly what to do in this case, especially because you do have correct intuitions!

We're going to close this issue for now, please open new issues if you have a chance to read over the edits to chapter 15 made in #898 and have further thoughts ❤️

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

No branches or pull requests

4 participants