Skip Menu |

This queue is for tickets about the Moo CPAN distribution.

Report information
The Basics
Id: 84000
Status: rejected
Priority: 0/
Queue: Moo

People
Owner: Nobody in particular
Requestors: jakob.voss [...] gbv.de
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: (no value)
Fixed in: (no value)



Subject: coerce only gets the first argument
Given a Mooed object with coerced attribute has foo => ( coerce => sub { ... } ) The coercing sub only gets the first argument. In particular one cannot support multiple arguments of writers: $thing->foo( 'x', 'y' ) # 'y' not passed to coercing but ignored I had to hack support around the accessor for my particular use case (see <a href="http://prepan.org/module/nXWJ8Y9sBhE">see MooX::AutoConstructor at PrePAN</a>). Support of multiple arguments would be cleaner, more flexible and probably faster.
Attributes are always expected to be single items, and special casing this for coercions seems wrong. It also breaks consistency with setting attributes in constructors. It would seem much more sensible for your code to work with an arrayref: $thing->foo( ['x', 'y'] );
Attributes are single items but they can origin from any number of values. Sure one can explicitly flatten or coerce to a single value like this: Show quoted text
> $thing->foo( some_flattening_sub('x', 'y', 'z') );
However, I found it more convenient to put this into coercing. Sure it's a matter of coding style. If it "seems wrong" to you, I'll to have hack another solution. See <a href="http://prepan.org/module/nXWJ8Y9sBiu">Class::Accessor::Coerce</a> at PrePAN and <a href="https://github.com/nichtich/Class-Accessor-Coerce/blob/master/lib/Class/Accessor/Coerce.pm#L28">the examples in its documentation</a>. The downside of this solution is that one must refer to the coercing sub at two places for the constructor and for the accessor. Show quoted text
> It also breaks consistency with setting attributes in constructors.
No it does't. One just cannot provide more than one argument in the constructor, so what? Show quoted text
> It would seem much more sensible for your code to work with an > arrayref: > > $thing->foo( ['x', 'y'] );
Yes, and one could use has references as well: Show quoted text
> $thing->person( { given => $given, surname => $surname } );
Do I really have to argue that the following forms are more convenient? Show quoted text
> $thing->sum( 1, 3, 2 ); > $thing->person( given => $given, surname => $surname );
You're right, ->sum(1, 2, 3) is a lot clearer. Generally though, doing something like that points to a user mistake, so we require accessors to refer to a single value. Fortunately we *do* have a way around (heheh) this. The following would both work: has sum => ( is => 'rw', coerce => sub { return List::Util::sum(@{$_[0]}) if ref $_[0]; return $_[0] }, ); around sum => sub { my ($orig, $self, @rest) = @_; if (@rest) { return $self->$orig(\@rest) } else { return $self->$orig } }; This gives you the nice API that you want, but also keeps Moo consistent with Moose and what users have expected for a long time. Enjoy!
Thanks, that's a useful workaround which makes sense. I put it into a reusable method (not sure about the name and whether a MooX module makes sense): sub arguments_as_ref { around @_ => sub { my ($orig, $self, @rest) = @_; $self->$orig( @rest ? \@rest : () ); } } The performance could surely be improved by support in the core of Moo, e.g. has sum => ( is => 'rw', coerce => sub { return List::Util::sum(@{$_[0]}) if ref $_[0]; $_[0] }, arguments => 'ref' ); but for now, the solution is enough.
On Sun Mar 17 08:16:16 2013, VOJ wrote: Show quoted text
> Given a Mooed object with coerced attribute > > has foo => ( coerce => sub { ... } ) > > The coercing sub only gets the first argument. In particular one > cannot > support multiple arguments of writers: > > $thing->foo( 'x', 'y' ) # 'y' not passed to coercing but ignored
This behaviour is consistent with Moose. Marking rejected.