clone() in getter: convenient for the caller; doesn't need any borrows; might result in unnecessary clones when I just want to access the value for reading.
clone() in the setter: has to deal with borrows; might result in unnecessary clones when I pass a newly created Arc.
clone() in the caller: least convenient for the caller; cluttering the code; full control about the clone()operations
Rust is all about giving explicit control: sacrificing a performance optimization, even if minor, to save a .clone() call does not go in that direction.
So, regarding the getter, returning a borrowed Arc is definitely the best, and regarding the setter, it should require an owned value.
If you really want ergonomics for the setter, you could use a custom trait:
Hmmm ... I just noticed that I cannot cast the references into a trait object any more: Rust Playground
fn get_arc(&self) -> &Arc<dyn MyTrait> {
// mismatched types
//&self.my_arc
// cannot return reference to temporary value
// cannot move out of borrowed content
//&(self.my_arc as Arc<dyn MyTrait>)
// non-primitive cast: `&std::sync::Arc<()>` as `&std::sync::Arc<dyn MyTrait>`
//&self.my_arc as &Arc<dyn MyTrait>
}
Another downside is, that I cannot create new values any more (cannot return reference to temporary value) - just return references to existing values.
To return reference of something, you should hold its owned value somewhere. Arc<dyn MyTrait> contains fat pointer so it even has double size of Arc<MyType>.
I have a trait that demands a return type of &Arc<RwLock<dyn MyTrait>> but I have a field of type Arc<RwLock<MyStruct>> (where MyStruct: MyTrait).
This works fine without the reference but then I'd always have to clone the result.
Yeah, that's not possible in general. To return a reference of Arc<RwLock<dyn MyTrait>>, you must hold this 2-pointer-wide type somewhere, not something that can be coerced to this type.
As @Hyeonu pointed out, you cannot return a &Arc<dyn Trait> unless you hold the actual Arc fat pointer somewhere in memory (e.g., in your example, you could return &self.traited_arc).
So you need to return &Arc<TypeImplementingTrait>. In your example, that can be &Arc<()>, or, if you wish some type erasure, &Arc<impl Trait>: