6

I've seen a few instances of this sort of pattern in Rust code:

trait Task {
    fn run(self: Box<Self>) -> i32;
}

struct SomeTask {}

impl Task for SomeTask {
    fn run(self: Box<SomeTask>) -> i32 {
        1
    }
}

fn main() {
    let task: Box<Task> = Box::new(SomeTask {});
    task.run();
}

Now... I understand the intent of this code, it's a trait that implements the self consuming pattern:

fn foo(self);

Ok... but what?

You can qualify self as something other than Self? Are there other things self can be, other than Self, &Self, &mut Self and, apparently Box<Self>?

Why does this feature exist, given you can already do this without it:

trait Runnable {
    fn run(self) -> i32;
}

trait Task {
    fn value(&self) -> i32;
}

struct SomeTask {}

impl Runnable for Box<Task> {
    fn run(self: Box<Task>) -> i32 {
        self.value()
    }
}

impl Task for SomeTask {
    fn value(&self) -> i32 {
        1
    }
}

fn main() {
    let s: Box<Task> = Box::new(SomeTask {});
    s.run();
}

It feels a little bit like this is left-over cruft from missing box foo syntax, where they really wanted to allow fn foo(box self), but it was inconsistent without box syntax existing in the first place... but I still don't understand what the functional purpose of this receiver type is.

(Edit, since the related question is ancient and doesn't specifically answer the question. See https://github.com/rust-lang/rust/issues/44874 for the ongoing discussion around this issue; tldr: Apparently arbitrary receiver types are a thing, and they're on the way but not stable yet)

Doug
  • 32,844
  • 38
  • 166
  • 222

0 Answers0