Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When should I make a Moose class immutable when I'm actually using ->meta?

Tags:

perl

moose

Normally I would finalize a class at compilation via __PACKAGE__->meta->make_immutable at the end of the class. However, when should I be making a class immutable that composes roles into itself at runtime? Should I even be doing so to get better performance or is this imcompatible with make_immutable? make_immutable seems to speed up instantiation of the object, but does it do anything once the object is instantiated?

For example, something along the lines of:

BUILD {
  my $self = shift;
  use Module::Load;

  ### Use the arguments passed in to determine roles applicable to 
  ### this instance of the object. Load and apply roles.
  for my $role ($self->_determine_roles()) { 
    load $role;
    $role->meta->apply($self);
  }

  ### $self is now a Class::MOP::Class::__ANON__... anonymous class
  ### Should I then be saying I'm done mutating it with something like this?
  ### can make_immutable even be run on an object instance and not a package?
  $self->meta->make_immutable;
}

Even if the code above works for a single package, what happens when a object reblesses itself with the 'Foo' role, resulting in a anonymous class, then a second object blesses itself with a 'Foo' (becoming that same anon class) then 'Bar' role? Is it going to work correctly when the second object blesses itself into the immutable first anonymous class, then tries applying the role to the now-immutable anonymous class to create a new anonymous class?

From reading the docs on Moose::Meta::Class, it appears only a class can be immutable, not instances of objects. If so, should I just be ignoring make_immutable as I am mutating my classes?

like image 674
Oesor Avatar asked Mar 28 '11 17:03

Oesor


1 Answers

You should be doing make_immutable as usual at the bottom of your class, and not worrying about it at all in your BUILD.

When you apply a role to an instance at runtime it doesn't modify the instance's class to apply the role (that would be messy and horrible and affect all other instances of that class); it creates a new anonymous class that inherits from your class and does the requested roles as well, and then reblesses the instance into that class. Since the original class isn't being modified there's no issue of whether it's open/mutable or not.

You actually can do $self->meta->make_immutable after the role application — it will immutabilize the newly-created anonymous class — and for completeness you probably should. But it will only give a small benefit, since most of what make_immutable does is to make the constructor faster, and the new class's constructor doesn't run anyway.

If you want to see the details of how role application to instances works, you should peek at the source of Moose::Meta::Role::Application::ToInstance.

like image 128
hobbs Avatar answered Oct 16 '22 23:10

hobbs