# &Rc, &Arc as method receivers?

**URL:** <https://internals.rust-lang.org/t/rc-arc-as-method-receivers/11069>\
**Category:** Uncategorized\
**Created:** [October 8, 2019, 8:26am UTC](https://internals.rust-lang.org/t/rc-arc-as-method-receivers/11069 "2019-10-08T08:26:00Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![glandium](https://avatars.discourse-cdn.com/v4/letter/g/3d9bf3/32.png) [@glandium](https://internals.rust-lang.org/u/glandium)\
**Post date:** [October 8, 2019, 8:26am UTC](https://internals.rust-lang.org/t/rc-arc-as-method-receivers/11069/1 "2019-10-08T08:26:00Z")

</div>

[#56805](https://github.com/rust-lang/rust/pull/56805) stabilized `Rc` and `Arc` as method receivers, making it possible to do something like:

```rust
struct Foo;
impl Foo {
    fn foo(self: Arc<Self>) {}
}

```

However, that forces every call to the method to either have a disposable `Arc` that won't be used afterwards already, or to `Arc::clone`, meaning a forced increment _and_ later decrement of the ref counter. (Same with `Rc`). That can be quite a waste. It gets even worse when the method needs to call other methods that also take `self: Arc<Self>`.

Stupidly reduced example to illustrate, but the following is not allowed:

```rust
struct Foo;
impl Foo {
    fn foo(self: Arc<Self>) {}
    fn bar(self: Arc<Self>) { self.foo(); self.foo(); }
}

```

And the only correct way, currently, would be:

```rust
struct Foo;
impl Foo {
    fn foo(self: Arc<Self>) {}
    fn bar(self: Arc<Self>) { Arc::clone(&self).foo(); self.foo(); }
}

```

The generated code for `fn main() { Arc::new(Foo).bar(); }` looks like:

```rust
playground::main:
	pushq	%rbx
	subq	$16, %rsp
	movl	$16, %edi
	movl	$8, %esi
	callq	*__rust_alloc@GOTPCREL(%rip)
	testq	%rax, %rax
	je	.LBB5_7
	movq	%rax, %rbx
	movaps	.LCPI5_0(%rip), %xmm0
	movups	%xmm0, (%rax)
	lock addq	$1, (%rax)
	jle	.LBB5_8
	movq	%rbx, 8(%rsp)
	lock subq	$1, (%rbx)
	je	.LBB5_3
	movq	%rbx, 8(%rsp)
	lock subq	$1, (%rbx)
	je	.LBB5_5
(snip)

```

That is extra useless traffic on the atomic refcounter, and real use-cases would actually have to call `Arc::clone` too, adding one more `lock addq`. (BTW, it's worth noting the compiler is not assuming the refcounter is not supposed to be decremented more times than it was incremented, and tests whether the refcount reaches 0 on each decrement, although it's not possible for it to reach 0 on the first decrement, since it was increased first (apart from other unsafe code doing nasty stuff to the refcount)) (BTW2: I'm actually surprised the compiler is not able to figure out this reduced testcase is just doing nothing).

A way to address this would be to allow `&Arc` as a method receiver.

So, would it make sense to stabilize `&Arc` and `&Rc` as method receivers, in advance of the full arbitrary self types support? I guess this should also be extended to `&Box` and `&Pin`, actually, for similar reasons. It's actually worse for e.g. `Box` because it means calling a method with `self: Box<Self>` will always drop the `Self`.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [October 8, 2019, 8:47am UTC](https://internals.rust-lang.org/t/rc-arc-as-method-receivers/11069/2 "2019-10-08T08:47:13Z")

</div>

There's an open PR for this, currently still waiting on FCP being triggered before it can be merged:

> <https://github.com/rust-lang/rust/pull/64325>

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [October 8, 2019, 11:03am UTC](https://internals.rust-lang.org/t/rc-arc-as-method-receivers/11069/3 "2019-10-08T11:03:46Z")

</div>

> A way to address this would be to allow `&Arc` as a method receiver.

If you don't need a copy of the already-existing `Arc`, why don't you just take `&Self` instead of `Arc<Self>` (or `&Arc<Self>`)?

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [October 8, 2019, 1:39pm UTC](https://internals.rust-lang.org/t/rc-arc-as-method-receivers/11069/4 "2019-10-08T13:39:21Z")

</div>

The entire point of this is to take ownership, so it seems to require exactly what it should. If the need to have an `Arc` gets in your way, you want a `&self` method.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [October 8, 2019, 1:41pm UTC](https://internals.rust-lang.org/t/rc-arc-as-method-receivers/11069/5 "2019-10-08T13:41:03Z")

</div>

There are usecases where `&Arc` makes a lot of sense, e.g. if the method _may_ need to take ownership. Instead of pre-cloning the `Arc` and passing it to the method just to have it dropped, you can pass a reference to an `Arc` in and it can clone it if it needs to.

---

<div class="post-metadata">

**Author:** ![rpjohnst](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rpjohnst/32/9524_2.png) [@rpjohnst](https://internals.rust-lang.org/u/rpjohnst)\
**Post date:** [October 8, 2019, 5:44pm UTC](https://internals.rust-lang.org/t/rc-arc-as-method-receivers/11069/6 "2019-10-08T17:44:26Z")

</div>

A potential alternative might be an equivalent to C++ `shared_ptr`'s `enable_shared_from_this` helper. If you can guarantee a type is only ever exposed to consumers via an `Rc` or `Arc`, then it is safe to provide a method on `&self` to upgrade the reference.

---

<div class="post-metadata">

**Author:** ![mbrubeck](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mbrubeck/32/174_2.png) [@mbrubeck](https://internals.rust-lang.org/u/mbrubeck)\
**Post date:** [October 8, 2019, 6:22pm UTC](https://internals.rust-lang.org/t/rc-arc-as-method-receivers/11069/7 "2019-10-08T18:22:51Z")

</div>

@nikomatsakis wrote a bit about this pattern as an aside in [this `gnome-class` post](http://smallcultfollowing.com/babysteps/blog/2017/05/02/gnome-class-integrating-rust-and-the-gnome-object-system/#mapping-between-gnome-and-rust-ownership).

---

<div class="post-metadata">

**Author:** ![glandium](https://avatars.discourse-cdn.com/v4/letter/g/3d9bf3/32.png) [@glandium](https://internals.rust-lang.org/u/glandium)\
**Post date:** [October 8, 2019, 10:28pm UTC](https://internals.rust-lang.org/t/rc-arc-as-method-receivers/11069/8 "2019-10-08T22:28:46Z")

</div>

> [@rpjohnst](#):
>
> If you can guarantee a type is only ever exposed to consumers via an `Rc` or `Arc`

That's exactly what `self: &Arc<Self>` would be useful for: guaranteeing consumers are only using an Arc.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [October 9, 2019, 4:33am UTC](https://internals.rust-lang.org/t/rc-arc-as-method-receivers/11069/9 "2019-10-09T04:33:55Z")

</div>

Would it make sense for std to add a `BorrowedArc<'_, T>` for this use case (and make it a method receiver)? Yes, you can do this with `unsafe` and `fn new() -> Arc<Self>`, but there's no real reason for this not to be a safe pattern, even when only used sometimes.

The advantage of doing this is avoiding the double indirection of `&Arc`.

```rust
// and all of this for `Rc` as well ofc

pub struct Barc<'a, T: ?Sized> {
    ptr: NonNull<ArcInner<T>>,
    phantom: PhantomData<&'a T>,
}

impl<'a, T: ?Sized> Barc<'a, T> {
    pub fn upgrade(this: Self) -> Arc<T> { ... }
}

```

---

<div class="post-metadata">

**Author:** ![asa-z](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/asa-z/32/6771_2.png) [@asa-z](https://internals.rust-lang.org/u/asa-z)\
**Post date:** [October 10, 2019, 7:21pm UTC](https://internals.rust-lang.org/t/rc-arc-as-method-receivers/11069/10 "2019-10-10T19:21:03Z")

</div>

I think the bloat of an additional type here is probably not merited given that the pattern is clearly expressed in `&Arc`. The one concern I would have is if `&Arc` could confuse people new to rust into thinking there being only a single indirection.

---

<div class="post-metadata">

**Author:** ![dhm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dhm/32/4879_2.png) [@dhm](https://internals.rust-lang.org/u/dhm)\
**Post date:** [October 10, 2019, 9:22pm UTC](https://internals.rust-lang.org/t/rc-arc-as-method-receivers/11069/11 "2019-10-10T21:22:24Z")

</div>

Nested self receivers seem like the way to go for this. In the meantime, for those interested in tinkering with such methods, you can fake add `inherent` methods on `ARc<YourType>` through a helper (preferably sealed) trait, so that `&Self` in these methods is thus `&ARc<YourType>` ([playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=9d83d2964b6292e37fd2fc36ec0e9321)).

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [January 8, 2020, 9:22pm UTC](https://internals.rust-lang.org/t/rc-arc-as-method-receivers/11069/12 "2020-01-08T21:22:29Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
