Boxed self in a trait method?


#1

Hi, I want to make a sort of FSM, where the state is represented by a boxed trait object. This trait then has a method that returns a new state or the original one. My problem is that I don’t know how to pass the self argument as a box instead of a reference or value. Is it possible somehow?

An non working example:

trait State {
    fn update(Box<self>) -> Box<Self>;
}

struct X {};
impl  State for X {
    fn update(Box<self>) -> Box<X> {
        if something {
            self
        }
        else {
            Box::new(SomethingElse::new())
        }
    }
}

#2

Using -> Box<Self> is probably not want you want in that example, as that would mean that X implementing State could only return Box<X> (because Self is X), as opposed to any Box<State>.

For the method itself, fn updated(self: Box<Self>) should work.

Here’s a working example:

trait State {
    fn update(self: Box<Self>) -> Box<State>;
}

struct Foo {
    thing: bool,
}

impl State for Foo {
    fn update(self: Box<Self>) -> Box<State> {
        if self.thing {
            self
        } else {
            Box::new(Bar::new())
        }
    }
}

struct Bar;

impl Bar {
    fn new() -> Bar { Bar }
}

impl State for Bar {
    fn update(self: Box<Self>) -> Box<State> { self }
}

Playground: https://play.rust-lang.org/?gist=71fdc5bac4c8904dd210&version=stable


#3

Thank you! It didn’t occur to me that self: Box<Self> would work.

You are also right about returning Box<State> instead of Box<Self>, but that one was just a typo :slight_smile:


#4

Why are you using a trait anyway? Wouldn’t a FSM be better implemented directly as an enum?


#5

Actually this is kind of a translation form how I would do it in C++ :slight_smile:

I need the states to have methods and potentially a lot of data. It is for a game and a state here is “in main menu”, “in settings dialog” or “in game”. The “in game” state then contains the game object which in turn has all the scene data. I also want the state to occasionally hold another state (when there is a dialog opened over the game, for example).

With enum I’d have to have match on the first level of all the methods and I would have to rely on RVO for not copying too much stuff around.


#6

Ok, then a trait is probably the way to go.


#7

Hi.

Does this idiom fn f(self: Box<Self>) imply a special invocation syntax (like fn f(self) does) and if so, where is this documented?


#8

Hm, I’m not sure what you mean by “special invocation syntax” here.


#9

Sorry, I wasn’t clear.

I mean obj.f() when obj: Box<ImplType> and definitions

trait Fred { fn f(self: Box<Self>) }

impl Fred for ImplType { fn f(self: Box<Self>){...} }

I could try it out I suppose, but I haven’t seen it in any of the doc I’ve been reading. It means I can use the “method” invocation style as opposed to the UFCS, and appropriate refs will be removed and/or added.

Are there any other special declaration forms for the method invocation call syntax?


#10

Ah yeah, the definition, not invocation. Cool, thanks for clarifying :smile:

Right now, this is a way that Box is special; that is, these are sugar for:

self      -> self: Self
&self     -> self: &Self
&mut self -> self: &mut Self 

In theory, this means that you could use the self: SomeType<Self> syntax for any SomeType<T>, but for now, you can only use Box<T>. Eventually this restriction will be lifted.

It’s not super well documented because it’s weird and awkward and almost never what you need, once it’s not a special case, it will deserve real docs.


#11

Thank you for responding.

I understand that these are sugar for what you say. The invocation syntax is what I did mean, because you can only use the obj.f() syntax for methods. And methods are declared in this special way using self.

And if we didn’t use self, then we would have to use the UFCS to call the function.

I’m afraid I didn’t follow why the three ‘sugar’ definitions would imply anything about self: SomeType<Self> parameter declarations. This doesn’t fit these patterns. So the explanation ought to include a reason why self: Box<Self> (and it’s &/mut cousins) should be regarded as method declarations and not merely function declarations.

Shouldn’t it?


#12

The Rust book covers methods, albeit it doesn’t mention the Box<Self> flavor (perhaps for the reason @steveklabnik mentioned) and it distinguishes them from functions.

I think the SomeType<Self> aspect is that, in the future, you might be able to invoke methods on Self when it’s wrapped in a SomeType. Currently only Box<Self> has that privilege.


#13

Thank you. Yes, that would seem to be the current state of play: self: Box<Self> means you can invoke methods on boxed Selfs. By the way methods are functions with special declaration syntax and special invocation syntax; both ‘sugar’ for more verbose declarations.

Presumably self means a Box<Self> in that method implementation body, though, and what return type you would expect is not clear. I suppose update-in-place might be useful, leaving it boxed, but the reference/mutable versions hurt my brain.

Could you (or anyone) give a reasonable use-case for the Boxed “method” notation? This would help me to internalise it. At present I cannot see the need.


#14

Which method implementation body are you referring to?

It’s a bit nichey and likely why it doesn’t receive as much coverage. But, see the start of this thread for an example usecase.