Too much Rc::clone()

I have some types which look like this:

pub type RenderFaceMeshLink = Rc<RefCell<RenderFaceMesh>>;
pub type RenderMaterialLink = Rc<RefCell<RenderMaterial>>;
pub type RenderTextureLink = Rc<RefCell<RenderTexture>>;
pub type RendererLink = Arc<Renderer>;

The purpose is that the "Link" types put reference counts on the non-"Link" types, each of which owns something in a GPU. When "drop" is called for one of the non "Link" types, the appropriate GPU asset is removed at the GPU level. So this is encapsulating GPU memory management.

This all works fine.

But, since Rc and Arc are not copyable, I'm constantly writing clone calls whenever I need to pass these things around.

viewable_object.add_face(Arc::clone(&renderer_link));
viewable_face.update_material(Rc::clone(&error_material_link));
viewable_face.update_mesh(Rc::clone(&cube_mesh_link));

This seems unnecessarily wordy. Is there some idiom I'm missing here?

You can make those functions to take reference of the link instead and clone it internally when needed. It may improve the code if the function doesn't need the owned [A]Rc in many cases.

I'd say the idiom you are searching for is "avoid shared mutable state".

I'm not privy to your particular use case, but in general you often see people pull out Rc<RefCell<T>> because they don't have a solid ownership story - often people reach for runtime object lifetime management because they don't really know when their resource will be destroyed or there is no one component in charge of it (i.e. single responsibility principle).

You might also find that it's not necessary for a component to own a reference to some GPU resource and you can just pass around a &RenderMaterial or &mut RenderFaceMesh as method arguments every time it they are needed.

That's how I prefer to do things anyway. It may or may not line up with the way your code is currently designed.

1 Like

Most parts of the system (it's a client for a virtual world) have little or no shared mutable state. This part is the section that manages the visible assets, and it has a lot of shared mutable state. A ViewableObject has Meshes, Textures, and Materials. These are often shared with other ViewableObjects, so as to not fill the GPU with duplicates. When the last user of something no longer needs it, it's time for it to leave the GPU, which is handled in the "drop" function. There's constant churn as the user moves around, new objects come into range and old objects leave, and things move in-world. Oh, and there are multiple threads - changing the world refreshing the display, and dealing with incoming assets are concurrent.

This is a case where shared mutable state is extremely useful. It's easier to debug this in Rust than in C++, too.

Yes, I think I can repackage some of the Rc::new(), etc. to be done inside some functions. I just wanted to make sure I wasn't missing some common idiom for doing this.

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.