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
==========================*/

Reply via email to