35

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.

2 Answers 2

42

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!)

Sign up to request clarification or add additional context in comments.

7 Comments

So I can reasonably expect that other library types besides Box will be supported at some point in the future?
Yes, supporting other pointer types is the major motivation for the change in syntax.
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.
Maybe interesting to note that in addition to e.g. Arc<T>, self can also be &Arc<T> or &mut Arc<T>. Probably most use cases would prefer just &T, but maybe some methods would like to clone the Arc that T is sitting in.
@huon please add a link to doc.rust-lang.org/reference/items/associated-items.html#methods which documents all of the currently supported variants
|
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.

2 Comments

I would add that despite the name, arbitrary self types aren't quite "arbitrary", but must (transitively) deref to Self. So self: Arc<Self> and self: &Arc<Self> are fine, but self: Vec<Self> isn't. (Of course the details are subject to change before stabilization.)
This answer is outdated now.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.