speshak has asked for the wisdom of the Perl Monks concerning the following question:

I have an object that contains an array of other objects. I want to iterate over the array, calling a method on each of the contained elements:
package Foo; ... sub doStuff { my $self = shift; foreach my $obj ($self->{objs}) { $obj->doSomethingElse(); } }
Now when I try to run this I get:
Can't call method "doSomethingElse" on unblessed reference..
When I do a Data::Dumper on $obj I get the all of the array contents, and the loop only happens once. So the issue appears to be that I'm not iterating over what I think I am. Insight more than welcome. :)

Replies are listed 'Best First'.
Re: Iterating over an array of objects, within an object?
by Crackers2 (Parson) on Dec 19, 2006 at 01:54 UTC

    To say it a bit shorter than GrandFather, $self->{objs} is a reference to your array. A reference is a scalar, so all you're iterating over is that one reference.

    What you want instead of course is to iterate over the elements of your array. So to get from your array reference to your array, you need to dereference it. So you need @{$self->{objs}}, which turns your code into:

    package Foo; ... sub doStuff { my $self = shift; foreach my $obj (@{$self->{objs}}) { $obj->doSomethingElse(); } }

      Actually I said it in one line, although I should have put that line at the top of my reply rather than at the bottom.

      The code not only illustrates the fix, but in a subtle fashion shows that you can have objects without packages in seperate files, or even requiring full blown constructors - and realising that can be a real Ahh moment.


      DWIM is Perl's answer to Gödel
Re: Iterating over an array of objects, within an object?
by GrandFather (Saint) on Dec 19, 2006 at 01:45 UTC

    Without getting all messy with packages and such, the following may help:

    use warnings; use strict; my @objs; push @objs, bless {me => "Object $_"} for 1 .. 3; my $obj = bless {objs => \@objs}; $obj->doStuff (); sub doStuff { my $self = shift; $_->doSomethingElse() for @{$self->{objs}}; } sub doSomethingElse { my $self = shift; print "Visited $self->{me}\n"; }

    Prints:

    Visited Object 1 Visited Object 2 Visited Object 3

    It was the dereferencing that bit you. Note @{$self->{objs}} in the code above.


    DWIM is Perl's answer to Gödel