Back when Curtis Poe was at Booking.com we were in the the first team to use Moose (actually Mouse at the time) for anything serious. While it saved us a lot of time overall that we'd otherwise have spend on writing boilerplate code we found the Moose support for type constraints to be fairly inflexible for our purposes.
Moose will simple die if you pass it a value that violates a type constraint, in an environment where you control the whole stack this is usually what you want, but when you're dealing with data from other people and user-supplied parameters you often want to handle the situation more gracefully.
Curtis pointed this out on the Moose mailing list, and quickly found that this was something covered in the Moose FAQ.
I hacked up something that would change the behavior globally, but of course this is something you want to do on a per-attribute level. Jesse Luehrs provided a basic implementation of it which I expanded on, and which I've now uploaded to the CPAN as MooseX::Attribute::TypeConstraint::CustomizeFatal
The module allows you to tweak what Moose does when a type constraint fails on a per-attribute level. The default is to die as Moose does by default, but you can also make it warn and accept the bad value, or warn and fall back on the default value, or just silently ignore the bad value and fall back on the default value.
I thought I'd write my own practical version of Moose::Manual::Unsweetened by converting Hailo away from Moose. The resulting hack passes all of Hailo's tests but not surprisingly it wasn't worth it.
I wanted to see if I could get the startup time of Hailo down since Moose doesn't incur a runtime penalty once all your classes have been constructed. Here's how much time it takes the three version of Hailo to start up and reply to input, and how much (RSS) memory they use:
- Hacky Perl OO: 100ms / 5.6MB
- Mouse: 150ms / 7.4MB
- Moose: 350ms / 12MB
Mouse seems to get a lot of flak within Moose circles for not being a 100% complete Moose implementation. I previously wrote about how you can maintain dual support for Moose and Mouse in a previous posting.
In future programs I'll be using Mouse as the default with a fallback to Moose. It does everything I need from Moose and doesn't suffer from the high startup time / memory use that's frequently cited as an objection to Moose-based applications.
If that doesn't convince you, here's a mouse riding a frog:
Hailo has been converted from a Moose application to a hybrid Mouse/Moose application for release 0.20.
This brought its memory usage from 28MB to 20MB. Hailo is around 4.000 lines and the patch required to make it Mouse + Moose compatible (including testing both at
make test time) is just under 500 lines.
As well as reduced memory use another big plus is the reduced startup time.
hailo(1) starts with Mouse in around 250…
I'd heard that MooseX::Method::Signatures incurred a substantial runtime performance hit. I wanted to test if that was true so I tried converting Hailo to use it. The result: Yes, it's slow:
Here's how long it takes (real time) to train Hailo with a new brain, the command is:
time hailo --brain megahal.brn --train /tmp/fortune.trn --no-progress
- Without MX::MS: 11.37s
- With MX::MS…