in reply to a State machine with Roles - possible?

These slides are confusing!

Initially I read the line The object will appear to change its class and had the same idea like salva to simply re-bless an object into a new class.

But the shown mixin code seems to operate on classes not instances (just like roles in Moose do) ?!?

Could you please elaborate what you're exactly intending to do?

UPDATE

seems like I found the answer on my own:

Similarly, Object.extend(module, ..) adds the instance methods from each module given as a parameter. However, extend adds the methods to one instance, not to all instances.

Cheers Rolf

( addicted to the Perl Programming Language)

Replies are listed 'Best First'.
Re^2: a State machine with Roles - possible? (class or instance)
by salva (Canon) on May 29, 2013 at 15:42 UTC
    It seems Ruby mixology adds support for per-object mixins.
      Yep, but I think it's a core feature.

      edit: see extend

      Cheers Rolf

      ( addicted to the Perl Programming Language)

Re^2: a State machine with Roles - possible? (class or instance)
by james2vegas (Chaplain) on May 30, 2013 at 09:03 UTC
    Seems Moose allows you to attach roles to instances, not just classes, with Moose::Util::apply_all_roles($applicant, @roles) by creating a new anonymous class with the object's previous class as superclass and with the roles applied, and then reblessing the object into that class. Not sure the other role implementations have easily accessible methods to do this.


    UPDATE: using Moo::Role or Role::Tiny this seems to work bless $object, Moo::Role->create_class_with_roles(blessed $object, @roles); (replace Moo::Rule with Rule::Tiny for less Moo-ness, and import blessed from Scalar::Util)
      Well yesterday I meditated about ways to implement this in Perl...

      While I don't know the Moose guts, I remember that Moose was said to stay compatible to classical OO, mostly just adding syntactic sugar. ²

      So I suppose that the normal search-path isn't manipulated in Moose.

      This led me to 2 possibilities to implement this (rather JS-ish) requirement.

      > by creating a new anonymous class with the object's previous class as superclass and with the roles applied,

      Thats the first approach I thought about. But I'm worried about side effects. How transparent is this new class in the middle, does the instance still officially belong to the superclass?

      FWIW my approach to implement the OP's state machine would certainly be to openly create sub-classes for each state with a common superclass defining the interface.

      Like this state-changes could simply be realized with reblessings.

      Different roles could still be applied to these "state"-classes, can't see any need to avoid inheritance here.

      The other approach to have individual methods per instance could defining an attribute hash instance_methods which holds names => sub {} for each instance-method.

      However calling this indiviual methods would imply the need to inherit equally named interface methods in the class to delegate the call.¹

      Alternative an AUTOLOAD mechanism comes into mind, but these methods would have the lowest priority in the search path then.

      BUT I can't see any need to implement a state machine this way.

      IMHO the euphoria for mixins in Ruby was taken a bit to far.

      Cheers Rolf

      ( addicted to the Perl Programming Language)

      UPDATE

      ¹) such that  $obj->my_meth() does something like $self->{instance_methods}{my_meth}->(@_).

      ²) plz correct me if I'm wrong!

        Thanks for the discussion LanX :-) I think that you're looking for something too complicated, and that Roles just do the trick. (i might well be wrong). Here is the Perl code for getting the same behavior as the Ruby code from the slides (it could all be shorter and put in the same file, with MooseX::Declare - but some people might not have it installed):

        test.pl

        use feature ':5.16'; use strictures; use Door; use Moose::Util qw( apply_all_roles ); my $main_door = Door->new; # The Door is Closed $main_door->knock; # knock knock # Open it apply_all_roles($main_door, 'Opened'); $main_door->knock; # just come on in! # Close it apply_all_roles($main_door, 'Closed'); $main_door->knock; # knock knock # Bug ?? say 'Why does this not print ??' if $main_door->DOES('Closed');

        Door.pm

        package Door; use Moo; use feature ':5.16'; use Moose::Util qw( apply_all_roles ); sub BUILD { apply_all_roles($_[0], 'Closed'); # default State at construction } sub knock { say 'DEFECT: a door should never be nor opened nor closed'; # This method will be overriden by the Roles # (should never be printed) } 1;

        Closed.pm

        package Closed; use Moose::Role; use feature ':5.16'; sub knock { say 'knock knock'; } 1;

        Opened.pm

        package Opened; use Moose::Role; use feature ':5.16'; sub knock { say 'just come one in!'; } 1;

        Which does what is expected (output written as comments in test.pl).

        But it has several problems:

        • To check whether a Door is closed or opened, i need to check if the object DOES any of these two Roles. Unfortunately, DOES seems to not work, for a Role instanciated on an object. This might be a bug in Moose::Object::DOES. (see the last line of test.pl)
        • When a door is Closed, it is still Opened at the same time. I need to be able to unapply_role(). Which is what they do in the Ruby example with 'unmixin'. And it's my initial question in this thread: how to do it in Perl?

        If there were simple solutions to these two problems, then i think we could implement complex State machines with multidimensional states.

        There is here someone who asked pretty much the same question as me, with a pretty good example of multidimensional State machine: a warrior who can be turned into a Zombie, poisoned, made stronger, turned into a Chipmunk, or all of these at the same time. The answer to that person's question was an alternative solution with aspects. I would still prefer the solution with Roles, which are more flexible, and in my opinion clearer.

        Was that clear? Helpful? Did i miss your point LanX?