#!/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"; #### 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; }