3

I started to migrate a couple of Perl modules to Moo but got stuck because the setter/writer can only have one single argument (can't it?). This also applies to coercing:

package MyThing:
use Moo;
use Scalar::Util qw(blessed);
use SomeOtherThing;

has foo => (
  is => 'rw',
  coerce => sub {
      return $_[0] if blessed($_[0]) and $_[0]->isa('SomeOtherThing');
      return SomeOtherThing->new( @_ ); # does not work, because @_ == 1
  },       
);

Here is a simple use case:

package MyApplication;
use MyThing;

$thing = MyThing->new;
$thing->foo( 'some', 'values'); # would like to have this shortcut
$thing->foo; # expected a SomeOtherThing

# must use this ugly form instead
$thing->foo( SomeOtherThing->new('some', 'values') );

Is there an easy way to implement accessors that support setting with multiple arguments?

Jakob
  • 3,570
  • 3
  • 36
  • 49

2 Answers2

4

Yes, use array references:

use Carp;
has foo => (
  is => 'rw',
  coerce => sub {
    return $_[0] if blessed($_[0]) and $_[0]->isa('SomeOtherThing');
    ref $_[0] && ref $_[0] eq 'ARRAY' or croak "foo: arg must be a SomeOtherThing or array reference";
    return SomeOtherThing->new( @{$_[0]} );
  },       
);

Later...

$thing->foo(['some', 'values']);

You could also use a hashref instead, if the object needs to accept key/value arguments.

With full Moose, you'd instead write a type co-ercion from ArrayRef to SomeOtherThing.


Disclaimer

I can see this being useful in some cases (e.g. passing x/y co-ordinates instead of creating a Point object) but I would use it with caution.

Doing this increases the coupling of your classes: MyThing is now not just depending on SomeOtherThing's methods, but also its constructor - if you add new fields to SomeOtherThing, you may need to change both MyThing and all the modules that call MyThing's foo method. Ouch!

rjh
  • 49,276
  • 4
  • 56
  • 63
  • 1
    Thanks for showing a workaround. Still, it's a workaround but not what I was looking for. I have found a way to do it and crafted a perl package: https://github.com/nichtich/MooX-AutoConstructor – Jakob Mar 15 '13 at 22:18
1

Access to multiple arguments in setters in not possible with the current version of Moo, so I wrote a Perl module to extend this feature. It's currently experimental, so feel free to comment Class::Accessor::Coerce at PrePAN.

Jakob
  • 3,570
  • 3
  • 36
  • 49