A plan for fixing _fix_metaclass_compatibility

[email protected] (Dave Rolsky)
Newsgroups perl.moose
Message-ID <[email protected]>
I'm discussing this here cause the plan is kinda long, and wouldn't work 
well in IRC.

First, the problem ...

With Moose::Util::MetaRole, it's quite easy to end up with a metaclass 
that is not Moose::Meta::Class. Generaly, it's a subclass of MMC with 1+ 
roles applied to the subclass. Let's call a subclass that differs from its 
parent only by the roles it does a "role-only subclass".

Right now, Moose does not handle these sorts of role-only subclasses well 
when trying to determine if two classes have compatible metaclasses. If 
two classes each have different role-only subclasses as their metaclass, 
Moose complains that these metaclasses aren't compatible.

Here's a more concrete example:

   ClassA
      |
      |
   ClassB

ClassB inherits from ClassA. Here's the metaclasses:

              Moose::Meta::Class
              /                 \
             /                   \
         MetaSubA              MetaSubB
      (for ClassA)             (for ClassB)

The two metaclass subclasses are each role-only subclasses (doing the 
roles RoleA and RoleB respectively).

When we declare ClassB as a subclass of ClassA, Moose dies. What _should_ 
happen is that Moose detects that the two metaclasses are role-only, _and_ 
that they share a common ancestor. Then it can simply make a new metaclass 
for ClassB which does both RoleA and RoleB, as a subclass of MetaSubA.

Poof, now they're compatible again.

So that's what I'd like to implement. The algorithm goes like this:

1. Look for a common parent class between the two metaclasses (often this 
will end up being Moose::Meta::Class). If there is none, there's an 
incompatibility. If there are multiple common parents, give up, because I 
don't want to deal with multiple inheritance ;)

2. For each class in the chain from a metaclass to the common parent, see 
if that class is a role-only subclass.

3a. If all of these subclasses are role-only subclasses _in both chains_, 
we just need to combine all the roles done in both chains, and make a new 
subclass for said roles.

3b. If any of the classes in the chains are _not_ role-only subclasses, we 
have a real incompatibility, and die just like we do now.

The catch is how to determine if a given metaclass is a role-only 
subclass, and this is where we get to changing Class::MOP and Moose to 
support this.

The basic algorithm I've thought of to detect a role-only subclass looks 
like this. Compare all of this class's attributes and methods to its 
parent. For any that are specific to the class, see if they come from a 
role.

The last part is what's not really possible with today's CMOP & Moose. We 
have no good way of knowing the source of an attribute or method, and I 
want to change that.

My plan is the following:

* Whenever we add a method (add_method or alias_method), we need to accept 
more than just a name and a sub reference. Instead, we can take a 
parameter like "source_role" (in Moose) or maybe just "source_package" to 
make it generate and applicable to CMOP.

* We can do the same thing for attributes. Additionally, I'd like to be 
able to specify an associated_attribute for methods generated from an 
attribute. This I want to add just cause we can, and it seems like useful 
info.

There's one potential stumbling block here. Right now, Method objects are 
not generated until someone asks for one via an introspection method. To 
make all this work I think we'll need to generate them as part of 
add_method, or even just accept such an object in add_method. This means 
we'll be generating these objects during compile/load time, and paying the 
cost up front.

So what do people think of this plan?

I'd like to start working on it soon, because the metaclass compatibility 
thing is biting me in actual code, and working around it is kind of a 
pain, plus Moose should just get this stuff right anyway.


-dave

/*==========================
VegGuide.Org
Your guide to all that's veg
==========================*/
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.