Chaining in Moose, Mouse, Moo and Mo

Recently, I created a new issue on Github for Mo (https://github.com/ingydotnet/mo-pm), suggesting a chained interface:

package Hello;
use Mo;
has 'first';
has 'second';

my $hello = Hello->new;

# current implementation
$hello->first('foo');
$hello->second('bar');

# result
print $hello->first;  # foo
print $hello->second; # bar

# chaining (suggested)
$hello->first('foo')->second('bar');

The suggestion was rejected, providing the following reasons:

"Neither Moo nor Moose nor Mouse does this by default, and nor do the vast majority of pre-Moose accessor builders."

While this is in line with Mo guidelines

"Mo will attempt to not do the things it does in an incompatible style to the Moose family.",

the question is: why not switch to a chaining interface in Moose, Mouse and Moo, and Mo? Should this even become the default behaviour?

9 Comments

Have you considered a case when your accessors do fail?

Lots of time they return the actual value that was set (that in some cases can be different from the argument). Therefore, you can use it in conditionals, for instance, because the "set" value will be returned...

If you want this specific behavior in Moose, there is a MooseX:: for that (see https://www.metacpan.org/module/MooseX::Traits::Attribute::Chained ).

As for why it is not default in Moose. To start with it is because the convention is to return the value set (not just in Perl, but in most languages (NOTE: jQuery is not a language and while its API is useful, it is a specific case and not something to be applied across the board)), and because chained accessors seem useful up until you begin to explore the edge cases.

The obvious one being the possible failure case (as komarov pointed out) and the more subtle one being the API complexity it creates. If an accessor always returns the value stored, no matter if it is get or set behavior, then it is very easy to predict behavior. And while your simple case of accessors that store strings might seem to save you some typing, a really application would store complex objects and in those cases you very well might want to call methods on those objects rather then have to do another get call to get at them.

I am not disagreeing that in some cases chained accessors might be useful, but you really don't want all your accessors behaving this way all the time. Now Moose gives you the power to pick and chose (again, see the MooseX:: I linked to above, it does that), but now you are creating even more API complexity because now some of your methods chain and some don't.

If you really want this, I suggest instead of trying to add to the core of Mo, you simply use the plugin API that ingy has created to write your own Mo extension (similar to what was done with the MooseX).

- Stevan

Additionally, changing the default behavior of Moose at this point would break the over 1400 CPAN modules which depend on Moose and that behavior. Not to mention the amount of DarkPAN code it would break, this kind of massive API change is not something that can even be considered.

And again, there is a MooseX for that, as there is for almost anything like this. Moose was built to be extensible in this way, so that if you didn't like the default, you could change it in a safe and confined manner.

- Stevan

Mm, is there a MooseX for that? :)

I like method/attribute chaining, but it also makes getting return value a pain. The MooseX strategy is smart here.

About Forward Ever

user-pic I blog about Perl.