Info
This post is auto-generated from RSS feed The Rust Programming Language Forum - Latest topics. Source: Method with access to Arc on dyn without cloning Arc
Methods sometimes need access to the Arc
managing self
. This is easy: fn f(self: Arc<Self>)
(to own the reference count) or fn f(self: &Arc<Self>)
(to borrow it with the possibility of owning a count later by clone()
). The former has the issue that every method call consumes self
so many calls need o.clone().f()
which is very unergonomically and it's slower because of the forced atomic inc/dec. But the &Arc<T>
version works, so whatever.
However, if I want to pass around an Arc<dyn Trait>
, then we have a problem. The Arc<Self>
version does actually work fine, however &Arc<Self>
does not because that makes the trait dyn incompatible. The former isn't good for the reasons discussed above.
Is there a known work around for this issue? I'd like to use core
/std
if possible, but I am open to other crates. (I think I know how to implement a custom ref-counted type for this by allowing the user to write methods against what is effectively &ArcInner<Self>
, though I haven't worked through it fully, so maybe it won't work either.)
I appreciate any comments or advice. Thanks!
Here is some code that shows what I'm talking about concretely.
mod owned_ref {
use std::sync::Arc;
// self is an *owned* reference count to a Tr. Every call must inc/dec even
// if the method does not need to own a count.
trait Tr {
fn f(self: Arc<Self>);
}
struct St;
impl Tr for St {
fn f(self: Arc<Self>) {}
}
fn main() {
// ERROR: Use of moved value because self is consumed.
let r: Arc<dyn Tr> = Arc::new(St);
r.f();
r.f();
// TERRIBLE: Requires clone() on every call *and* performs inc/dec on
// every call.
let r: Arc<dyn Tr> = Arc::new(St);
r.clone().f();
r.clone().f();
}
}
mod borrowed_ref {
use std::sync::Arc;
// self is a *borrowed* reference count to a Tr. Calls do not require
// inc/dec, but method can create an owned ref count.
trait Tr {
fn f(self: &Arc<Self>);
}
struct St;
impl Tr for St {
fn f(self: &Arc<Self>) {}
}
fn main() {
// ERROR: Tr is not dyn compatible.
let r: Arc<dyn Tr> = Arc::new(St);
}
}
fn main() {}
Errors:
error[E0382]: use of moved value: `r`
--> src/main.rs:20:9
|
18 | let r: Arc<dyn Tr> = Arc::new(St);
| - move occurs because `r` has type `Arc<dyn owned_ref::Tr>`, which does not implement the `Copy` trait
19 | r.f();
| --- `r` moved due to this method call
20 | r.f();
| ^ value used here after move
|
note: `owned_ref::Tr::f` takes ownership of the receiver `self`, which moves `r`
--> src/main.rs:7:14
|
7 | fn f(self: Arc<Self>);
| ^^^^
help: you can `clone` the value and consume it, but this might not be your desired behavior
|
19 | r.clone().f();
| ++++++++
error[E0038]: the trait `borrowed_ref::Tr` is not dyn compatible
--> src/main.rs:47:16
|
36 | fn f(self: &Arc<Self>);
| ---------- help: consider changing method `f`'s `self` parameter to be `&self`: `&Self`
...
47 | let r: Arc<dyn Tr> = Arc::new(St);
| ^^^^^^^^^^^ `borrowed_ref::Tr` is not dyn compatible
|
note: for a trait to be dyn compatible it needs to allow building a vtable
for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
--> src/main.rs:36:20
|
35 | trait Tr {
| -- this trait is not dyn compatible...
36 | fn f(self: &Arc<Self>);
| ^^^^^^^^^^ ...because method `f`'s `self` parameter cannot be dispatched on
= help: only type `borrowed_ref::St` implements `borrowed_ref::Tr`; consider using it directly instead.
error[E0038]: the trait `borrowed_ref::Tr` is not dyn compatible
--> src/main.rs:47:30
|
36 | fn f(self: &Arc<Self>);
| ---------- help: consider changing method `f`'s `self` parameter to be `&self`: `&Self`
...
47 | let r: Arc<dyn Tr> = Arc::new(St);
| ^^^^^^^^^^^^ `borrowed_ref::Tr` is not dyn compatible
|
note: for a trait to be dyn compatible it needs to allow building a vtable
for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
--> src/main.rs:36:20
|
35 | trait Tr {
| -- this trait is not dyn compatible...
36 | fn f(self: &Arc<Self>);
| ^^^^^^^^^^ ...because method `f`'s `self` parameter cannot be dispatched on
= help: only type `borrowed_ref::St` implements `borrowed_ref::Tr`; consider using it directly instead.
= note: required for the cast from `Arc<borrowed_ref::St>` to `Arc<dyn borrowed_ref::Tr>`
11 posts - 4 participants
🏷️ rust_feed