Planet Moose - August 2014

Welcome to Planet Moose, a brief write up on what's been happening in the world of Moose in the past month, for the benefit of those of you who don't have their eyes permanently glued to the #moose IRC channel, or the MetaCPAN recent uploads page.

It's now a year since the first Planet Moose. I'm surprised I've managed to keep it up for a whole twelve months. (Though it's not always been posted promptly on the first day of the month!)

If you'd like to contribute some news for next month's issue, you can do so on the wiki.

Moose

Moose 2.1211 has been released containing some documentation updates and minor changes to Moose::Exporter.

More interestingly, three Moose 2.13xx trial releases have been uploaded to CPAN. The major new feature so far is improved support for overloaded operators, especially in roles, eliminating the need for MooseX::Role::WithOverloading.

Moo

Moo 1.006000 has been released. This has slightly improved performance for type constraint checks, and adds support for coerce => 1 in attribute declarations, provided you are using a type constraint framework that exposes an appropriate coercion API. (Type::Tiny does.)

OO Jenga

For some time there have been discussions on IRC about the problems of OO Jenga. For example, what happens when a Moose class subclasses a Moo class that subclasses a Class::Tiny class? Does it all work smoothly?

The major problem that tends to occur in this sort of situation is with BUILD methods being called too early, or sometimes multiple times. Let's consider the case of a Unicorn class which subclasses Horse. Horse is built with Class::Tiny, and Unicorn with, say, Moose. So when you do:

    Unicorn->new(name => "Twilight Sparkle", horn => "medium", colour => "mulberry");

then the first thing the Unicorn will do will be to call the parent constructor using something like:

    $class->SUPER::new( \%params );

So now, Horse::new gets called to handle the parameters it knows about (name and colour). Horse::new is the constructor supplied by Class::Tiny. Once it's finished handling the parameters, what it will do is call a BUILD sub in every level of $class's inheritance hierarchy, starting at the bottom (i.e. just above UNIVERSAL). Once it's done that, then it returns $self. This is where it gets interesting...

Unicorn::new comes back into play. It handles the horn parameter. Now that all the parameters have been handled, it now also calls the BUILD sub in every level in $class's inheritance hierarchy!

So all the BUILD subs have been called twice. Horse wasn't aware that Unicorn was planning on calling them, and Unicorn wasn't aware that Horse had already called them. Whatsmore, the first time they were called, the horn parameter hadn't been properly handled yet! Yowch!!

What can be done? Can't Horse::new notice that it's been called by Unicorn::new (a child class constructor) and thus avoid calling BUILD? No, that doesn't quite work. The problem is that Unicorn::new might need not call Horse::new just once! Perhaps the Unicorn class definition includes something like:

     has friends => (
        is      => "ro",
        isa     => ArrayRef[ InstanceOf["Horse"] ],
        default => sub { [ Horse->new(name => "Pinkamena Pie") ] },
     );

So a typical call of the Unicorn constructor might end up calling the Horse constructor once because Horse is the parent class of Unicorn, and again when it builds the default value for friends.

There isn't really any neat solution to this. When calling the parent constructor, Unicorn really just needs to tell Horse on this particular method call, please don't call BUILD. But how should Unicorn indicate this request? The solution that the developers of Moose, Moo, and Class::Tiny have settled on is to accept a parameter called __no_BUILD__ that tells the constructor not to call BUILD methods.

So:

    SomeClass->new( foo => 1, bar => 2, __no_BUILD__ => 1 );

will perform the normal SomeClass construction, but prevent BUILD from getting called. It is not intended that you should ever supply this parameter yourself in normal code - it's merely a way for the various OO frameworks to co-operate with each other.

Expect to see this feature rolled out in Moose, Moo, and Class::Tiny over the next few months.

In other news...

1 Comment

*lol* at the easter egg :)

Leave a comment

About Toby Inkster

user-pic I'm tobyink on CPAN, IRC and PerlMonks.