Moose announcements and writings

Before Moose 2.1000, Moose's Num type used Scalar::Util::looks_like_number, which recognizes" 1223 ", NaN, Inf, "0 but true", etc. as numbers. In future releases, Num will only accept "123", 123, "1e3", 1e3, ".0", "0.0" etc. You can still get the older behaviour by using the LaxNum type provided by the MooseX::Types::LaxNum module. Please see this RT ticket for more details.

It's almost July, which means that it's time to start looking at the next major release of Moose, 2.0200. In addition to the changes that have been released in the minor revisions of the 2.00 series, this release will also include some additional, larger changes, the main ones being type constraint inlining and some changes to the way we generate inlined methods.

Type constraint inlining

When you define a type, you typically only specify how the type differs from some parent type. Currently, as a way to speed up type constraint checking, you can use the optimize_as option to define a validation subroutine to be used in place of checking the parent constraint followed by the current constraint's check. This helps, but could be better.

In 2.02, you will be able to use the inline_as option instead, to define a code snippet to use when inlining this type constraint, avoiding even the subroutine call overhead in accessors and constructors. Based on some simple benchmarks, this speeds up accessors by 30-40% and constructors by 10-30%, depending on the type constraints used and what else the methods are doing:

Because inline_as provides all of the functionality that optimize_as provided, optimize_as will be deprecated in 2.02, and eventually removed.

Method generation

Constructors and accessors are generated as closures. For instance, when you pass "default => sub { ... }" as an attribute option, that sub is saved, and then closed over when the accessor is generated (if the attribute is lazy), something along the lines of:

Previously, we used to close over a lot of meta-objects directly, out of convenience, but this makes deparsing hard because of the many links metaobjects have between each other (try using Data::Dump::Streamer to deparse a Moose-generated constructor!). More importantly though, this gets in the way of some future optimizations we're hoping to be able to do.

The actual effects of this are mostly only visible if you're writing extensions that require using the closed-over variables that were removed ($attr, $meta, $type_constraint_obj, etc). If you were, you'll have to either adjust your inlining code to use the new variables that are provided, or override the environment that Moose uses when compiling generated methods to add them back. Feel free to stop by #moose if you have questions about how to do this.

Finally, one obstacle to this being complete is that initializer subs receive the attribute metaobject as a parameter, which means we can't avoid closing over it in that case. This behavior is now deprecated, and will be removed in the future.

Other changes since 2.0008

The Array native trait now has a first_index delegation, which works just like first except that it returns the index of the match rather than the match itself.

Summary of changes during the 2.00 release cycle

Type constraint error messages now use Devel::PartialDump when possible, to display the data that failed the type constraint.

I'll be offering a one day Intro to Moose class at YAPC::NA 2011 in lovely Asheville, NC. To register, log in to the YAPC::NA site and then go to purchasing page. If you haven't registered for YAPC yet, you can buy your conference ticket at the same time too.

Intro to Moose

Join us for an interactive hands-on course all about Moose, an OO system for Perl 5 that provides a simple declarative layer of "sugar" on top of a powerful, extensible meta-model.

With Moose, simple classes can be created without writing any subroutines, and complex classes can be simplified. Moose's features include a powerful attribute declaration system, type constraints and coercions, method modifiers ("before", "after", and "around"), a role system (like mixins on steroids), and more. Moose also has a vibrant ecosystem of extensions as seen in the variety of MooseX:: modules on CPAN.

This course will cover Moose's core features, dip a toe into the meta-model, and explore some of the more powerful MooseX:: modules available on CPAN.

Students are expected to bring a laptop, as you will be writing code during the class. You will also be provided with a tarball a week or so before the class is scheduled, which will contain a directory tree skeleton and test files.

The release of perl 5.14.0 (and the simultaneous dropping of support for the perl 5.10 release series) is probably a good time to start looking at the support policy for the future of Moose. In particular, we do not yet have an official policy for the versions of perl we support.

For a historical perspective, Moose has required perl 5.8.1 since 2008 (at which point, 5.10.0 was the latest released version of perl). The requirement was bumped to 5.8.3 within the past year due to test failures on 5.8.1 (and none of the dev team having access to anything below 5.8.3), a move that met with basically no complaints.

Today, the latest released version of perl is 5.14.0. Relatedly, the earliest version of perl still supported by the perl5-porters is 5.12.0, and the earliest version of perl shipped with the latest release of any major Linux distribution except CentOS is 5.10.1 (and CentOS 6 should be released with 5.10.1 by the beginning of June). Supporting back to 5.8.3 now requires supporting 4 major releases (and 13 minor releases) dating back 7 years, and this isn't a very sustainable position to be in, given the limited resources of the Moose dev team. With new major releases of perl coming out yearly now, this will easily become overwhelming soon.

So with that in mind, Moose will be dropping support for perl 5.8 with the 2.06 release (in January of 2012). This will allow enough time for CentOS to get a stable release out that contains perl 5.10.1, and so everyone still running perl 5.8 should have an officially supported upgrade path by that point. As for what this actually means: we will not be immediately rushing in to start using smart matching and ripping out our existing 5.8 compatibility code. The specified version requirement will stay at 5.8.3. Moose will likely continue to work on perl 5.8 for a good while after next January. What this does mean, however, is that we will not be spending any more time fixing 5.8-specific issues. If critical bugs are found (unlikely at this point, but still possible), we will likely just bump our version requirement if no patch is forthcoming. New features are a fuzzier topic, but if someone comes along and implements a new Moose feature that requires features in perl 5.10, that patch will likely be accepted.

Our official support policy has been updated with this new information, and will be released with the next Moose release; it can be viewed here. If you have any questions about this policy, feel free to stop by #moose on irc.perl.org or contact the Moose mailing list at moose@perl.org.

As you may have noticed, there has been a bit of a delay in getting Moose 2 out. We've been doing a lot of testing, and a lot of fixing up of the Moose extensions (and a lot of being busy with things other than Moose), but we're finally ready for a release. Moose-1.9906-TRIAL has just made it to CPAN, and this will hopefully be the last dev release before 2.0000. If you've been holding off on testing the new Moose versions until things settle down and everything works again, now is the time to actually do that. If no serious bugs are reported in the next week or so, Moose 2.0000 will be released on Monday, April 11.

As mentioned earlier, this release includes some major refactorings of the internals. Therefore, a lot of MooseX modules had to be updated to take this into account. All of the latest versions of the MooseX modules should now work with both the current stable release, and the latest dev release of Moose, so you can upgrade all of these without any breakages.

The inverse of this is not true, however - many old versions of Moose extensions will break if you upgrade Moose without also upgrading them. When you upgrade to Moose 1.9906 (or Moose 2.0000), the installation process will warn if there are any outdated modules installed on your system that may stop working with the new Moose. Upgrading these modules is important in order to make sure everything continues to work. To make this process easier, Moose now ships with a script named 'moose-outdated', which scans through your system and prints the names of any modules it finds which conflict with the currently installed version of Moose. After upgrading Moose, a simple 'moose-outdated | cpanm' should bring you up to date. This functionality will continue to be provided and kept up to date in future versions of Moose.

Finally, I'd just like to highlight again the issue that Dave brought up in the previous post - make sure you aren't expecting role attributes to pick up the attribute metaclass of the class they're being applied to, as this will no longer happen. Read the previous post for more details about this.

Comments, questions, or issues with the Moose release candidate should be directed to #moose on irc.perl.org, the moose@perl.org mailing list, or Moose's issue tracker on rt.perl.org.

In this example, the foo attribute ends up with the
MooseX::SemiAffordanceAccessor::Role::Attribute trait applied to it behind
the scenes. This trait is what affects how accessors are named.

With the current version of Moose, these attribute traits are also applied
to attributes provided by roles:

package MyClass;
use Moose;
use MooseX::SemiAffordanceAccessor;
with 'MyRole';
has foo => ( is => 'rw' );

Any attributes provided by MyRole end up with the SemiAffordanceAccessor
naming scheme.

This is a huge stinking bug. The problem is that by applying this trait, we
have changed the interface provided by MyRole. One of the major uses of
roles is to provide a named interface, so this is bad.

With Moose 2.0, this bug is fixed. When we apply MyRole, the attributes
applied from the role no longer acquire the attribute traits of the consuming
class.

However, some people might have been taking advantage of this feature, writing
roles with the assumption that the consuming class uses a MooseX module.

The right thing to do is to use the relevant MooseX module in the role
itself. This is not possible with Moose 1.2x, but will be possible in Moose
2.0. The only catch is that the MooseX module has to explicitly support this.

For many modules, this is trivial. Let's take MooseX::SemiAffordanceAccessor
as an example. The code used to look like this:

Some MooseX modules don't have it so easy. If your MooseX applies traits to
the class metaclass as well as the attributes, making it work with roles is
much harder. We're planning to make this simpler in Moose 2.02, but for now
your best bet is to look at a module like
MooseX::Attribute::Deflator
for an example of how to do this. Basically, you have to have the role "pass
along" the class metaroles when the role is applied.

As a consumer of a MooseX module, updating to Moose 2.0 will be fairly
simple. If you want to apply a MooseX module to attributes in role, just use
the module in your roles.

We're currently working with MooseX authors to get their modules updated in
preparation for the Moose 2.0 release.

We're available on irc://irc.perl.org/#moose-dev to help you update your
module, or you can email us at moose@perl.org. Please contact us if you need
help updating your code.

Note, though, that calling Moose "the preferred OO framework" is a bit of puffery.
Some people prefer it, but I'll bet you most Perlers have never even looked at it.
Not only that, the fragmentation of Mouse, Moose, Moo, and whatever else out there
is starting to confuse people who haven't started yet (so it's a frequent question
I get).

Of course from inside the Modern Perl/Moose bubble it is hard to believe that people haven't heard of Moose. And while I do think Moose is seeping out more and more, brian, with his unique position of being a well known figure both inside and outside of the Perl community, is very much right about the confusion over Moose, Mouse, Moo, et al. So after much discussion with the other core Moose team I decided it was time to write a blog post to help clear things up.

Clearing up the Confusion

So of course we (the core Moose devs) believe that Moose is the best choice, but we are not so ignorant as to believe that Moose is the right choice for everyone and every environment. And it was this exact reason that brought about Mouse and which is currently driving the Moo effort. Additionally Moose has always tried it's best to not make you pay for features you don't use by doing things like compiling highly focused accessors and lazy loading features when possible, which, when taken to the extreme leads to modules like Class::Method::Modifiers and Role::Basic in which Moose features are extracted completely.

Moose vs. Mouse

So as I said, we think Moose is the best choice, but when Moose is prohibitive, either because of startup overhead or memory usage, then Mouse is currently the best choice and one we encourage. Period.

In reality, there is no fragementation here because Mouse is very much commited to maintaining surface Moose compatability and runs a fair portion of the Moose test suite successfully (minus the Meta-Object tests of course).

Additionally tools like Any::Moose allow you to defer your decision and/or provide both options when possible. There have even been a few MooseX:: modules ported to MouseX and while this practice is generally discouraged because there are simply too many moving parts to keep in sync, the need existed and so people obliged.

Moo is an experiment from the sick and twisted mind of mst to radically re-think how Moose goes about compiling all it's meta objects. It builds on ideas from even more experimental MooseX::Compile born from the equally twisted mind of Yuval Kogman and an earlier mst experiment called MooseX::Antlers.

While mst and a few other brave souls are actually using Moo successfully, it is currently only in very limited situations with very simple "baby" Moose code. And really in the end, if Moo succeeds, you won't even know it is there because it will just be part of how Moose does it's thing. It is at this point that the community may choose to deprecate Mouse, but we will cross that bridge when we come to it.

So again, no real fragmentation here either, it is all part of the grand plan.

Moose inspired

The Perl community has long prided itself as being an group of independent minded (cough stubborn cough) people who don't just jump on the shiniest bandwagon or take the easy way out. We are well aware that Moose is a lot of Kool-Aid to drink and is not the right choice for everyone. And obviously because of this Mouse is not useful to these people either. So this is where some of the Moose inspired modules come into play.

In some cases these modules are re-implementations of Moose features, in other cases they are parts of Moose that have been extracted because of their usefulness to others outside of Moose. Here is a short, totally noncomprehensive list ...

Class::Accessor - A "moose-like" feature was recently added to this old standby of Perl OOP

As we said above, the ultimate goal of Moose has always been to make writing good OO code in Perl a less tedious and repetitive process. While we think Moose is the best way to do that, it is understandable that sometimes you only need a small part of it and all these modules provide this. And really as long as they maintain some level of commitment to Moose compatability, this works for us because it still serves our ultimate goal.

So sure, a little fragmentation here, but with a compatability commitment these really just become gateway modules to Moose.

Moose itch scratching

And lastly, I wanted to touch on the number of modules that have been in some way inspired by or related to Moose development. This subject really deserves it's own blog post, but I think it is worth mentioning these modules.

Conclusion

So hopefully this helps clear up some of the confusion that brian has seen on his adventures outside of the Modern Perl bubble. One of the really interesting and beautiful things about Open Source software development and the CPAN community in particular is that it really is a true meritocracy and functions extremely well as highly organized chaos. The drawback to that is that sometimes we have to clear up some confusion like this, which when viewed against the benefits is not that bad at all.

A complaint that has come up multiple times over the past few months is that,
as important as Moose is becoming in the Perl ecosystem, it should be more
concerned with backwards compatibility. After a series of discussions, the
Moose development team has come up with a support policy that seems to satisfy
most people; you can read about it
here.
The main points are: Moose will be moving to a time-boxed release cycle of
three months between (major) releases. Bug fixes and minor features can be
added in between major releases as long as they don't break backwards
compatibility (and we will put more effort into making sure they don't). Major
releases can break backwards compatibility, but we will release at least one
(ideally more than one) trial release before the actual release comes out, so
that people can test their own systems with the new features, and report back
with issues they may have. We will also do our best to assist maintainers of
Moose extensions with updating their modules for major changes, but not to the
point of taking over maintainership of extensions that have become
unmaintained. If you rely on a Moose extension whose maintainer has abandoned
it, feel free to find someone willing to take up maintainership, and come talk
to us on #moose, we'll be more than willing to help you get up to speed.

Now, on to the fun part(: The next Moose release will contain several exciting
new improvements, both for users and extension authors. The first is that there
has been a significant effort to speed up Moose's compilation time, through
several means. The largest and most obvious is that Package::Stash, the module
that Moose uses to do its symbol table manipulation (for adding and retrieving
methods, among other things), has been rewritten entirely in XS. Since Moose
spends over a third of its compilation time doing symbol table manipulation,
this seemed like a good optimization target, and this turns out to have been
correct - it resulted in a 10-15% speedup across the board for Moose
application compile times. Another advantage to this is that it fixes a couple
(admittedly minor) long-standing bugs in the Class::MOP::Package API, since the
symbol table API available from pure perl has several inherent issues itself.
Another area that should see significant improvement is in code which uses the
native delegation attribute traits. Previously (ever since the rewrite in
1.15), the traits themselves were loaded lazily (i.e.
Moose::Meta::Attribute::Native::Trait::Bool wasn't loaded unless you actually
declared an attribute with traits => ['Bool']), but the implementations of each
native delegation were all loaded at once, when the trait itself was loaded.
This has been fixed, and should be another fairly large speedup for
applications which use only a couple native delegations from the traits they
use (which is the case the vast majority of the time). Finally, the way method
metaobjects are cached has been improved, which speeds up the introspection of
methods (which happens frequently during compilation) a small but noticeable
amount. Here are some links to some relevant profiling data (run on my netbook
under full profiling, which is why the times are so high): "perl -MKiokuDB
-e1" with Moose 1.19: 8.60s, "perl
-MKiokuDB -e1" with Moose git:
6.38s, "perl -MMarkdent::Simple::Document -e1" with Moose
1.19: 13.9s, "perl
-MMarkdent::Simple::Document -e1" with Moose
git: 10.6s. These changes should
have minimal compatibility impact (and none at all if you don't use the
Class::MOP::Package API); a more detailed discussion is in
Moose::Manual::Delta.

In terms of features, we have made a fairly significant change to how attribute
metaroles work. Previously, when a role was applied to a class, it would copy
the attributes from the role into the class using the class's default
attribute metaclass, prior to applying the traits specified in the attribute
definition. This is obviously incorrect with a bit of thought - attribute
metaclasses completely define how the attribute works, including things like
how accessors are generated. If a role contains an attribute and some methods,
those methods need to be able to know what method name the accessor is going to
be installed under, or the role won't work. A good example of this is a class
which uses MooseX::FollowPBP consuming a role which doesn't - currently, this
completely breaks the role. With this change, roles now have their own default
attribute metaclass, separate from any class. This also allows for an
additional feature - when writing extensions, you can specify the
'applied_attribute' option to the 'role' block in 'apply_metaroles' to specify
a set of default traits that all attributes defined in that role will receive
when they are applied to a class. This should work identically to the
'attribute' option in the 'class' block, and should allow extensions which add
default attribute metaroles (such as MooseX::Aliases) to work identically in
both classes and roles (unlike currently, where the trait must be applied
explicitly in role attributes). The downside to this is that it breaks
backwards compatibility in a potentially confusing way: if you were assuming
and relying on role attributes using the class's attribute metaclass, your
roles will break, and there isn't really a way to detect this. The solution
will be to use the same extensions in your roles that you do in the classes
that consume those roles, but as noted previously, attribute metaroles don't
currently work in roles. These extensions will be fixed by the time we make an
actual release.

Finally, there is also some good news for extension authors: the inlining API
should be much more sane, and the code itself should be much more readable, so
adding inlined method generation support to your modules which affect accessor
or constructor/destructor generation should be much, much easier now. Some
highlights include: the attribute metaclass and class metaclass controlling
entirely how the bodies of the methods they generate are created (so there
should no longer be a need to write accessor or constructor metaclass traits),
accessor generation in Class::MOP and Moose going through one much simplified
codepath (read: removed the obscene amount of code duplication between
Class::MOP and Moose), so figuring out how a given accessor is generated should
be pretty trivial now, and constructors now asking the attribute metaclass how
to initialize attributes at construction time, rather than doing it themselves
with a bunch of duplicated code (so in the case of simple attribute traits
which affect accessor generation, manually modifying the constructor generation
shouldn't even be necessary). The downside to this is, as you may have guessed,
the API for doing code inlining has been changed pretty radically. This will
require some work on the part of extension authors, in order to use the new API
(since there's not really a non-insane way to support both APIs), but again,
we'll be working with extension authors to make sure this happens before our
actual release, and we'll be releasing a few dev releases prior to the actual
release to allow people with non-CPAN code to have a chance to update their
code.

As far as a plan goes, we're looking to have our first trial release out by the
end of this month, and are aiming for the actual release to happen sometime in
late December or early January. If you have any questions about the new release
and support process, or about any of these new features, definitely let us
know - we're very open to feedback, either here, on the Moose mailing list, or
on #moose-dev on IRC.

Moose 1.18 (and 1.17) are again primarily bug fix releases. In particular, we've killed some bugs that were introduced in 1.15 with the changes to native delegations. If you're using native delegations in your code and you've already installed Moose 1.15 or newer, we strongly encourage you to upgrade.

This release also fixes some random older bugs that have been lingering in rt.cpan for a while.

Finally, this release moves Moose and all of its prereqs from Test::Exception to Test::Fatal. Test::Exception depends on Sub::Uplevel, a module that tends to break with changes in the Perl core. This should make Moose a little more robust against future core changes.