With the addition of Types::Standard, I finally like Moo.
Moo's implementation of Moose is complete enough that I don't miss whatever features are missing, fast enough that I don't see it showing up as a bottle neck in profiling, and stable enough that I rarely run into a bug.
Moo's meta class is compatible with Moose. That is, Moo classes and roles can extend Moose classes and roles and vice versa. Moo is measurably faster than Moose, this allows you to write some performance sensitive classes in Moo but still cleanly interoperate with the rest of your Moose classes.
Its support for Type::Tiny (via Types::Standard) really makes Moo shine. Types::Standard provides Moo with Moose compatible types and more. It fixes many of the ambiguities which plague Moose's type system.
A slim-line Moose-alike without the costs and features most people don't need (plus Moose compatibility if it turns out you did); easy to sell to folks concerned about the overhead inherent to Moose. Very much simplified my object-heavy code.
This is a quick response to dirk's review. Although the documentation may make the list of missing features sound like they're just mst's whims (and some probably are), there is sound reasoning behind many of them.
If you read Moose::Manual::BestPractices you'll see:
* Avoid lazy_build
* Don't use the initializer feature
* Use Moose::Meta::Attribute::Native traits instead of auto_deref
And, directly quoting from Moose's author regarding augment/inner: "Thankfully, only a small percentage of people actually grok this feature and of those people only a handful of them are crazy enough to try and use it."
Augment/inner is hard to implement right; there are serious bugs lurking under the surface of Moose's implementation. It wouldn't be especially valuable for Moo to add another broken augment/inner implementation to CPAN.
Moo is not compatible with Moose in the same sense that Mouse is, where you can just replace "use Moose" with "use Mouse" and almost everything Just Works.
Moo is compatible in a different way - Moo classes can consume Moose roles; Moose classes can consume Moo roles; Moose classes can extend Moo classes; etc. In my opinion this is a more useful kind of compatibility.
I like the overall idea of Moo, but the author claims to try to support Moose compatibility where technically possible, but then creates arbitrary incompatibilities because of personal preference and not because of technical limitations. These are the direct quotes from the pod:
- "initializer is not supported in core since the author considers it to be a bad idea",
- "No support for super, override, inner, or augment - the author considers augment to be a bad idea",
- "default" only supports coderefs, because doing otherwise is usually a mistake anyway",
- "lazy_build is not supported; you are instead encouraged to use the is => 'lazy'",
- "auto_deref is not supported since the author considers it a bad idea."
Moo is very adept at providing a very lightweight and quick way to provide 'Modern' object oriented interface. While it is true that Moo itself has dependencies, I have observed that they are fairly lightweight.
Sometimes, the lack of certain features in itself is a feature, and I think Moo expresses this very well.
Of course, the lack of features.. is well.. a lack of features. But for what it's worth, I find dealing with Moo's "lack" of features easier than dealing with M[ou]ose's larger featureset.
Also, I personally find Moo's stack traces are easier to read and understand.
Last week I ported an application from Mouse (Any::Moose) to Moo. Went without a hitch (well I did replace "with 'X', 'Y', 'Z';" to "with 'X'; with 'Y'; with 'Z';" as instructed in the Moo documentation). Startup time decreased significantly. Planning to move every Moose apps to Moo. Splendid!