0

In the example code below, I am defining a class Person that can have child objects of the same class.

When I invoke the printTree method, I am expecting the following output

Sam    Ram    Geeta

What I see instead is

SamRamRamRamRamRamRamRamRamRamRamR.....

Any hints on what I am doing wrong and how to achieve my goal?

package Person;

use Moose;

has name => ( is => 'ro' );

my @kids;

sub addChild {
    my ( $self, $name ) = @_;
    my $k = Person->new( name => $name );
    push @kids, $k;
    return $k;
}

sub printTree {
    my $self = shift;
    print $self->name;
    $_->printTree foreach ( @kids );
}



no Moose;

package main;

my $s = Person->new( name => "Sam" );
my $r = $s->addChild( "Ram" );
my $g = $s->addChild( "Geeta" );

$s->printTree;
Borodin
  • 126,100
  • 9
  • 70
  • 144
vijayvithal
  • 551
  • 1
  • 5
  • 13
  • 1
    Don't call `printTree` inside `printTree`. Btw, shouldn't `@kids` also be a property? – mpapec May 19 '17 at 08:13
  • 3
    Your `@kids` is a singleton inside the class. That means all objects share it. It's a bad idea. It should be a property. I'll write up an answer later. – simbabque May 19 '17 at 08:24

1 Answers1

6

The issue is that @Person::kids does not belong to any one instance, and you effectively end up with

@Person::kids = ($r, $g);
$s->printTree() loops through @Person::kids, calls
 $r->printTree() loops through @Person::kids, calls
  $r->printTree() loops through @Person::kids, calls
   $r->printTree() loops through @Person::kids, calls
    ...

You need to make it an attribute, e.g.

has kids => (
    isa => 'ArrayRef[Person]',
    traits => ['Array'],
    handles => {
        all_kids => 'elements',
        push_kids => 'push',
    },
    default => sub { [] },
);
sub addChild {
    my ($self, $name) = @_;
    my $k = Person->new(name => $name);
    $self->push_kids($k);
    return $k;
}
sub printTree {
    my ($self) = @_;
    print $self->name;
    $_->printTree foreach $self->all_kids;
}

You can check perldoc Moose::Meta::Attribute::Native::Trait::Array for other useful handles from the Array trait.

simbabque
  • 53,749
  • 8
  • 73
  • 136
ephemient
  • 198,619
  • 38
  • 280
  • 391