34

I wanted to create a method that only works where the self parameter was an Rc. I saw that I could use Box, so I thought I might try to mimic how that works:

use std::rc::Rc;
use std::sync::Arc;

struct Bar;

impl Bar {
    fn consuming(self) {}
    fn reference(&self) {}
    fn mutable_reference(&mut self) {}
    fn boxed(self: Box<Bar>) {}
    fn ref_count(self: Rc<Bar>) {}
    fn atomic_ref_count(self: Arc<Bar>) {}
}

fn main() {}

Yields these errors:

error[E0308]: mismatched method receiver
  --> a.rs:11:18
   |
11 |     fn ref_count(self: Rc<Bar>) {}
   |                  ^^^^ expected struct `Bar`, found struct `std::rc::Rc`
   |
   = note: expected type `Bar`
   = note:    found type `std::rc::Rc<Bar>`

error[E0308]: mismatched method receiver
  --> a.rs:12:25
   |
12 |     fn atomic_ref_count(self: Arc<Bar>) {}
   |                         ^^^^ expected struct `Bar`, found struct `std::sync::Arc`
   |
   = note: expected type `Bar`
   = note:    found type `std::sync::Arc<Bar>`

This is with Rust 1.15.1.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366

2 Answers2

41

Before Rust 1.33, there are only four valid method receivers:

struct Foo;

impl Foo {
    fn by_val(self: Foo) {} // a.k.a. by_val(self)
    fn by_ref(self: &Foo) {} // a.k.a. by_ref(&self)
    fn by_mut_ref(self: &mut Foo) {} // a.k.a. by_mut_ref(&mut self)
    fn by_box(self: Box<Foo>) {} // no short form
}

fn main() {}

Originally, Rust didn't have this explicit self form, only self, &self, &mut self and ~self (the old name for Box). This changed so that only by-value and by-references have the short-hand built-in syntax, since they are the common cases, and have very key language properties, while all smart pointers (including Box) require the explicit form.

As of Rust 1.33, some additional selected types are available for use as self:

  • Rc
  • Arc
  • Pin

This means that the original example now works:

use std::{rc::Rc, sync::Arc};

struct Bar;

impl Bar {
    fn consuming(self)                  { println!("self") }
    fn reference(&self)                 { println!("&self") }
    fn mut_reference(&mut self)         { println!("&mut self") }
    fn boxed(self: Box<Bar>)            { println!("Box") }
    fn ref_count(self: Rc<Bar>)         { println!("Rc") }
    fn atomic_ref_count(self: Arc<Bar>) { println!("Arc") }
}

fn main() {
    Bar.consuming();
    Bar.reference();
    Bar.mut_reference();
    Box::new(Bar).boxed();
    Rc::new(Bar).ref_count();
    Arc::new(Bar).atomic_ref_count();
}

However, the impl handling hasn't yet been fully generalised to match the syntax, so user-created types still don't work. Progress on this is being made under the feature flag arbitrary_self_types and discussion is taking place in the tracking issue 44874.

(Something to look forward to!)

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
huon
  • 94,605
  • 21
  • 231
  • 225
  • So I can reasonably expect that other library types besides `Box` will be supported at some point in the future? – Shepmaster Aug 23 '14 at 14:38
  • Yes, supporting other pointer types is the major motivation for the change in syntax. – huon Aug 23 '14 at 14:41
  • 6
    Returning to this many months later; any changes you know of in this area? The code as-is fails to compile, so nothing obvious yet. – Shepmaster Mar 30 '16 at 13:04
  • @Shepmaster see my answer below. – jbg Aug 08 '18 at 09:16
  • 1
    Maybe interesting to note that in addition to e.g. Arc, self can also be &Arc or &mut Arc. Probably most use cases would prefer just &T, but maybe some methods would like to clone the Arc that T is sitting in. – Jack O'Connor Aug 14 '21 at 20:31
  • 2
    @huon please add a link to https://doc.rust-lang.org/reference/items/associated-items.html#methods which documents all of the currently supported variants – Kamil Tomšík Dec 27 '21 at 19:48
  • I just needed a &Arc, and I'm glad it was there! The method used to receive a &self, but this simple change enables me to Arc::clone() it and send it into a tokio::spawn... – rsalmei Sep 22 '22 at 21:48
2

It's now possible to use arbitrary types for self, including Arc<Self>, but the feature is considered unstable and thus requires adding this crate attribute:

#![feature(arbitrary_self_types)]

Using feature crate attributes requires using nightly Rust.

jbg
  • 4,903
  • 1
  • 27
  • 30
  • I would add that despite the name, arbitrary self types aren't quite "arbitrary", but must (transitively) deref to `Self`. So `self: Arc` and `self: &Arc` are fine, but `self: Vec` isn't. (Of course the details are subject to change before stabilization.) – trent Aug 08 '18 at 15:02
  • 1
    This answer is outdated now. – mcarton May 12 '20 at 11:27