Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine

Comment on

( #3333=superdoc: print w/replies, xml ) Need Help??

Dear all,

I would like to use a 2d multidimensional array in Moose, but have a few questions. What is the proper way to build a two-dimensional array? In particular, I would like an array-of-arrays-of-objects which has a type 'ArrayRef[ArrayRef[Object]]'. Manipulating the outer dimension is easy enough through the native 'Array' methods such as push, pop, exists, etc. But the inner dimension is a little more tricky and I haven't found any information in my searches how to properly handle the inner arrays of objects. Here is what I have found:

#!/opt/local/bin/perl -w { package Obj; use Moose; has 'name' => ( is => 'rw', isa => 'Str', default => '', ); sub print { my $self = shift; print $self->name; } no Moose; __PACKAGE__->meta->make_immutable; } { package AoAoObj; use Moose; use Moose::Util::TypeConstraints; has 'arr2d' => ( traits => ['Array'], is => 'ro', isa => 'ArrayRef[ArrayRef[Obj]]', required => 1, default => sub { [] }, handles => { _push => 'push', }, ); sub addAoObj { my ($self, @obj) = @_; $self->_push([ @obj ]); } sub addInnerObj { my ($self, $index, @obj) = @_; #assert validity of objects pushed #onto inner arrays-of-objects my $constrAoAoObj = find_type_constraint('Obj'); for my $o (@obj) { $constrAoAoObj->assert_valid($o); } push @{ $self->arr2d->[$index] }, @obj; } sub print { my $self = shift; my $aref = $self->arr2d; for my $x (@$aref) { for my $y (@$x) { $y->print; print "\t"; } print "\n"; } } no Moose; no Moose::Util::TypeConstraints; __PACKAGE__->meta->make_immutable; } use strict; my $struct1 = AoAoObj->new; for my $x (0 .. 4) { for my $y ("A" .. "E") { my $myobj = Obj->new( name => "$y$x" ); $struct1->addInnerObj($x, $myobj); } } $struct1->print; $struct1->addInnerObj(3, 'Whammi'); # succeeds unless data validation +code is added to the method $struct1->print; print "END of struct1\n\n"; my $struct2 = AoAoObj->new; my $o1 = Obj->new( name => 'X1' ); my $o2 = Obj->new( name => 'Y1' ); my $o3 = Obj->new( name => 'Z1' ); $struct2->addAoObj($o1, $o2, $o3); # success; pushes [X1 Y1 Z1] $struct2->print; $struct2->addAoObj( qw/Whammi1 Whammi2/ ); # fails validation $struct2->print; print "END of struct2\n\n";

There is a lot going on here, so I will try to explain as simply as I can. I have two methods for pushing data on the 'arr2d' attribute. First, I have 'addAofObj'. This takes an array-of-objects and pushes it onto the outer array. Data validation works perfectly in this case, without any extra work. If I try to push an array-of-strings, for instance, the script fails as expected. This is illustrated at the bottom of the script with the $struct2 operations. The downside to this method is that I cannot extend rows; I can add more pre-formed rows, but they can't be extended.

The second method I use for pushing data is intended to overcome the limitation of the first method shown above. This method is 'addInnerObj'. In this case, I can extend any given row, but now there is no type validation unless I code it into the method. If I comment out the type validation steps, and just push the data provided by the caller:

sub addInnerObj { my ($self, $index, @obj) = @_; #assert validity of objects pushed #onto inner arrays-of-objects #my $constrAoAoObj = find_type_constraint('Obj'); #for my $o (@obj) { #$constrAoAoObj->assert_valid($o); #} push @{ $self->arr2d->[$index] }, @obj; }

no warnings or errors are triggered until further downstream when methods which don't exist are called on the elements of the array. This is illustrated with the $struct1 operations. In this case, if the caller provides a 'Str' instead of an 'Obj' type, the string is pushed onto the end of the row with no complaint from the class. It appears that using the builtin 'push' circumvents the Moose type validation infrastructure. I can correct for this by adding my own data validation, but I fear that this will come back to bite me if I subclass, or do other complex operations. So, back to my original question: what is the proper way to work with multidimensional arrays/structures with Moose? Thank you in advance for your help.

In reply to How do I work with multidimensional arrays in Moose? by paulymer

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?

    What's my password?
    Create A New User
    and all is quiet...

    How do I use this? | Other CB clients
    Other Users?
    Others scrutinizing the Monastery: (7)
    As of 2018-05-27 12:01 GMT
    Find Nodes?
      Voting Booth?