Traits, traits and more traits

So, a few days ago I posted about adding p6-style traits to the p5-mop, a couple days later I posted about how they helped me keep things simple when adding overload support to the p5-mop. Since this is a new approach and has not had the benefit of battle testing that the subclass/role heavy Moose approach has, I have been experimenting with it to see how far it can be taken.

On friday I wrote a test to see if I could add Moose style type-constraint checking. As you can see from the test that while the trait syntax was (kinda) nice, and it even worked when setting the attributes via the pseudo-lexical access.

class Foo metaclass TypedClass {
    has $bar is rw, type('Int');

    method set_bar ($val) { $bar = $val }
}

It required me to create a trait subroutine and 3 different meta-objects (subclass of Class, subclass of Attribute and subclass of Method (for some features not show in the above, you have to check the test to see them)). So while I did appreciate how simple the key parts of this example really were, I was bothered by how much scaffolding code I had to write to actually make it work.

Things got even trickier when Yuki Kimoto asked about doing attributes with weak-refs in a github issue. After some work I came up with this proof of concept, but I was really not happy with some of what I had to do in it.

I spent a good amount of time this weekend thinking of how I could go about this better. If this were Moose, I would have just applied a role to the Attribute meta-object instead of doing all the subclassing hoop-jumping. But, while that is conceptually simple, it requires a lot of underlying mechanics to work, and can be quite expensive. I wanted something that would give me the ability to do reasonably complex extensions without having to resort to subclassing or runtime role application and to almost entirely encapsulate the code inside the trait subroutine.

Then it hit me, why not just use the Observer pattern.

So I added an Observable role into the base MOP and during bootstrap we apply the role to Method and Attribute. By taking this approach I was able to completely remove the meta subclassing in my Moose style type-contraint example and create an extremely simple weak_ref trait that pretty much just works.

Of course, this is even more unexplored territory, but so far it feels really good and is built on a very well understood pattern, so I have high hopes. For now I am keeping this in an experimental branch until I am sure it is the right approach.

I think my next step is to get this working on 5.18 (I had some issues last time I tried), write up some basic docs and then put this out of CPAN as 0.01 and let CPANTesters run it through the ringer for me.

Leave a comment

About Stevan Little

user-pic I blog about Perl.