2

Can be done something like this in Perl?

package Person;
use Moose;

has 'friends' => ( is => 'rw', isa => 'Array', default => () );

I see that perl compiler doesn't accept this particular syntax, but do I use wrong syntax, or it is not possible at all? Do I have to use an array reference instead?

I'm pretty new to perl so the question is maybe dumb and I somehow feel the answer would be "no", but I haven't found any mention about it.

Thanks in advance

8
  • Seeing as you couldn't pass an array to an accessor, can't receive one from an accessor, or store an array a hash (or whatever else Moose objects might be), I don't even know what you even consider an "array attribute". Could you explain what you mean by an "array attribute"? Commented Nov 19, 2013 at 19:01
  • 1
    default => () makes no sense. It's just a weird way of writing 'default'. Commented Nov 19, 2013 at 19:02
  • Thanks, it basically means for me that it cannot be done. I'm still quite used to PHP where arrays are treated just like normal variables, so I didn't know that an array cannot be passed to an accessor etc. Commented Nov 19, 2013 at 19:05
  • Basically means what can't be done? Arrays are normal variables in Perl. Arrays can't be passed to accessors because arrays can't be passed to subs because subs can only take a list of scalars for arguments. Commented Nov 19, 2013 at 19:06
  • @amik: what you want to do can be done, but you aren't describing what you want to do. show some code that demonstrates how you want use this attribute Commented Nov 19, 2013 at 19:08

3 Answers 3

7

"List" has quite a few definitions. Presuming you mean an collection or ordered collection of Person objects, I'd use an array I'd pass to the accessor using a reference

has friends => (
   is      => 'rw',
   isa     => 'ArrayRef[Person]',
   default => sub { [] },
);

push @{ $o->friends }, $person;

for (@{ $o->friends }) {
   ...
}

You can add useful methods using Moose::Meta::Attribute::Native::Trait::Array.

has friends => (
   traits  => [qw( Array )],
   is      => 'rw',
   isa     => 'ArrayRef[Person]',
   default => sub { [] },
   handles => {
      push_friends => 'push',
   },
);

$o->push_friends($person);

for (@{ $o->friends }) {
   ...
}
Sign up to request clarification or add additional context in comments.

Comments

4

It's not quite what you're asking, but look at array traits - http://search.cpan.org/dist/Moose/lib/Moose/Meta/Attribute/Native/Trait/Array.pm. Since all of an instance's values are stored in a hashref, you can not store anything other than scalar values, meaning you need to use references. This handles all of the boilerplate you need to work with the internal arrayref.

package Person;
use Moose;

has 'friends' => ( is => 'ro', 
                   traits  => ['Array'],
                   isa => 'ArrayRef[Str]',
                   default => sub { [] },
                   handles => {
                                 all_friends    => 'elements',
                                 add_friend     => 'push',
                                 map_friends    => 'map',
                                 filter_friends => 'grep',
                                 find_friend    => 'first',
                                 get_friend     => 'get',
                                 join_friends   => 'join',
                                 count_friends  => 'count',
                                 has_friends    => 'count',
                                 has_no_friends => 'is_empty',
                                 sorted_friends => 'sort',
                             },

                 );

1 Comment

+1 I think array trait is the answer OP sought, along with needing to provide a coderef for default
0

As a simple answer that at least makes the get/set easier, you can write your own accessor functions to wrap an array ref into an array. For example:

package Person;
use Moo;

has 'friendsRef' => ( is => 'rw', default => sub { []; } );

## A 'set/get' wrapper for friendsRef
sub Person::friends {
  my ($self, @list) = @_;
  return @{$self->friendsRef} unless $#list>=0;
  return $self->friendsRef(\@list);
}

## Example bonus function for adding to list
sub Person::addFriends {
  my ($self, @list) = @_;
  return push(@{$self->friendsRef}, @list);
}

Example code usage could be:

my $p = Person->new();

$p->friends('Dave','Jerry');
print "Friends are: ",join(', ',$p->friends()),"\n";

$p->friends('Bob','Dave');
print "Friends are: ",join(', ',$p->friends()),"\n";

$p->addFriends('Joe','Cletus');
print "Friends are: ",join(', ',$p->friends()),"\n";

## Note that "$p->friends()" is not a scalar, it's a sub returning an array,
## so instead of "$#{$p->friends()}" you'd want "scalar($p->friends())"
print "Number of friends is ",scalar($p->friends()),"\n";

Output is:

Friends are: Dave, Jerry          
Friends are: Bob, Dave            
Friends are: Bob, Dave, Joe, Cletus                                 
Number of friends is 4            

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.