Stuck with Arc's in closures (Cursive)

I'm working on a TUI using Cursive and I'm stuck using Arc's in combination with closures.

The minimal example I made is already quite large, so forgive me for linking to this github repo.

The Controller owns the UI thread, owns the receiving end of a channel and it owns application state; in my hobby project a lot more happens in these parts but I kept it simple for this example.

The problem I'm facing is that I need to know at all times what the current selected_chain is. The user is able to select a different chain throughout the application (using a menubar that ultimately sends a message to the Controller through a channel) and at some other parts in the application I need to know the current selected_chain. When I initiate the app, I wrap the chain in a RwLock (so that I can change the contents of Chain at some point) and then in an Arc, so that I can use it across threads. Then I clone this selected_chain and give it to both the UI and to the Controller itself, so that I can use it in the UI whenever I need it (Cursive uses closures to send updates to the UI), and so that I can update it in the Controller whenever a message arrives in the channel.

But whenever I change the selected_chain in the app, the selected_chain in the UI parts 'sticks' to the value it was initiated with. And I don't understand why this happens, as ultimately, I'm still referencing the same selected_chain in the controller using clones.

What am I missing?

Each Chain in Controller is wrapped in its own Arc<RwLock<Chain>>. If you modified the Chain value, that would propagate, but you're not, only setting the selected_chain field or Controller — replacing one cloned Arc with a different, independent cloned Arc.

In order to have state that is shared, the modification must be of something inside an Arc<RwLock<T>> (or other shared + interior mutability combination of types).

One solution then would be selected_chain: Arc<RwLock<Option<Arc<RwLock<Chain>>>>> — the outer set is for picking a Chain and the inner set is for modifying a specific one. (If you do this, use type aliases or structs to wrap some part of the type and give it a less unwieldy name.)

There might be more elegant solutions, but I haven't reviewed your entire architecture (and am not familiar with cursive's requirements) — this is mostly just pointing out the problem.

Thanks, I understand now, my understanding of how Arc's work was a bit wrong. A struct would indeed be better for such nested types, thanks for the tip!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.