mainmatter / 100-exercises-to-learn-rust

A self-paced course to learn Rust, one exercise at a time.
https://rust-exercises.com
4.99k stars 861 forks source link

07_threads/10_patch The problem of updates is different? #117

Closed eugenefil closed 2 months ago

eugenefil commented 2 months ago

The section Multithreaded updates says:

The same strategy won't work in the current multi-threaded version, because the mutable reference would have to be sent over a channel. The borrow checker would stop us, because &mut Ticket doesn't satisfy the 'static lifetime requirement of SyncSender::send.

But SyncSender::send has no 'static lifetime requirement. Maybe you had in mind 'static lifetime bound put on closure by thread::spawn, which prevents using refs.

I actually tried to send &mut Ticket over a channel in the exercise code. Compiler starts asking you to put lifetimes everywhere, it becomes a mess, I didn't succeed. So, yes, you can't send &mut Ticket over a channel, but for a reason different from the one stated in the text.

I also tried to send &mut over a channel in a single-threaded case. That works ok.

c-git commented 2 months ago

While you are right in the literal sense, in this case because we are using multiple threads the lifetime bound implicitly becomes 'static for anything that is Send because how long a thread lives cannot be guaranteed. Thus to send anything over the channel it must be 'static

eugenefil commented 2 months ago

That literal thing is what confused me

'static lifetime requirement of SyncSender::send

I get what you're saying, although my understanding is that anything captured by the closure that is passed to thread::spawn explicitly has to be 'static simply because thread::spawn requires that by placing 'static bound on the closure.

Sending a non-static ref over a channel leads to sender's and receiver's generic T being inferred as that ref type with a lifetime. Receiver is captured by spawned thread's closure, so is bound by 'static and this is where violation happens: receiver's inferred type includes non-static lifetime. Rust traces that lifetime back to the original variable and spits that it "does not live long enough". I may be totally wrong though, I'm still learning.

c-git commented 2 months ago

That literal thing is what confused me

'static lifetime requirement of SyncSender::send

Fair enough, I'm sorry you got confused but the problem is when writing you get to do it once for the whole audience. For some this will go unnoticed (like me) and the simplified version works for them. And others will notice and understand it's been simplified. And then there is hopefully the smallest category where it leads someone into confusion. I almost spent a few hours today looking into something because of a comment just to realize I made an incorrect assumption about what the comment meant. Fortunately the author quickly disabused me of my misconception and I didn't go down that rabbit hole. But in your case I think you may have ended up learning in the process so it wasn't a waste.

Sending a non-static ref over a channel leads to sender's and receiver's generic T being inferred as that ref type with a lifetime. Receiver is captured by spawned thread's closure, so is bound by 'static and this is where violation happens: receiver's inferred type includes non-static lifetime. Rust traces that lifetime back to the original variable and spits that it "does not live long enough". I may be totally wrong though, I'm still learning.

I also consider myself a beginner. However, my understanding is that everything has a lifetime and it's just that most of the time it's able to be inferred so we don't need to write it out explicitly.

eugenefil commented 2 months ago

But in your case I think you may have ended up learning in the process so it wasn't a waste.

Absolutely.

LukeMathWalker commented 2 months ago

The correct phrasing would be "but SyncSender<&mut Ticket> wouldn't satisfy the 'static lifetime requirement introduced by std::thread::spawn." Thanks for raising this, I'll see how to reword the whole paragraph to make it more straight-forward.