Wednesday, June 3, 2009

Moose and DWIMery

So Ovid recently discovered that Moose does not create any accessors by default. Which was surprising to him and truthfully has surprised many people over the years. We on #moose have discussed this many times and the general consensus has always been to leave it as it is. I explain in the comments to Ovid's post why this is so, but I figured that for my inaugural blog post I should expand on this topic.

DWIMery and the Slippery Slope

DWIMery ("Do What I Mean"-ery) can be a very valuable thing when designing APIs but it does come at a cost. The more specific your API, the easier it is to DWIM since the option set is likely pretty small and defaults are usually obvious. But the more general your API, the harder it is to strike a balance. The problem gets even more so when you are designing something like an object system or a language. A system like Moose needs to not only support doing what I mean, but also doing what everyone else means as well. 

Opinionated Software vs. TimToady

Recently there has been a trend towards more "opinionated" software (Ruby On Rails) and even "opinionated" languages (Python).  The popularity of both these pieces of software shows that many people like this trend. However, Moose is Perl, and in Perl we subscribe to TIMTOWDI (There Is More Than One Way To Do It). On some level, you could say that opinionated software is actually the antithesis of TIMTOWTDI.

Now this is not to say that Moose is not opinionated or is somehow the pinnacle of  TIMTOWTDI. In fact Moose is actually pretty opinionated and I strongly believe that too much TIMTOWTDI is one of the reasons that Perl has the negative reputation it has for maintainability and code clarity. But what Moose does differently is to be humble about its opinions and make it easy (for some value of "easy") to override those opinions and inject your own.  

Chris Prather actually suggested just such a solution in one of his comments to Ovid's post. The syntax looks something like this:

package Foo;
use Moose -traits => ['ReadOnly'];

has 'bar';
has 'baz';

This could be accomplished by making a "trait" (the Moose term for a role that is applied to a meta-level object) which would affect the metaclass such that any time an attribute was created it would force a default read-only accessor to be created. While this sounds complicated it would actually be fairly simple, the trickiest part being dealing with merging your default read-only-ness with any user specified options.

Why Moose doesn't create accessors by default

Moose has always aimed to be as Perl-ish as possible, which means trying to embody the spirit of TIMTOWTDI. As I mentioned in one of my responses to Ovids post, the choice of which type of accessors Moose should create is not so simple. My personal inclination is towards generating simple read-only accessors, others might expect read/write accessors to be the default (which is what other common Perl OO modules like Class::Accessor provide). But this ignores the suggestions that Damian made in Perl Best Practices or the people who like semi-affordance accessors (->foo for reading and ->set_foo for writing) or the people who prefer public readers/private writers. The list can go on and on, and each and every one of these is an equally valid choice. 

In my mind the only solution when faced with all these differing and equally valid viewpoints is to actually favor none of them, but allow all of them. And of course, this is exactly what Moose does. I believe that this is most in keeping with the spirit of TIMTOWTDI and therefore the most Perl-ish. 

No comments:

Post a Comment