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

Greeings Monks,

How does one generate and track a bunch of objects? I'm thinking something like this?

Thanks

BROKEN CODE:

#!/usr/bin/perl use strict; use warnings; use Dog; my @pack = (); create_dog(15); foreach(@pack) { $_->bark; } sub create_dog { for (my $i=0; $i != $_[0]; $i++) { my $x = Test->new(); my $dog = \$x; push @pack, $dog; } }

Replies are listed 'Best First'.
Re: Tracking objects.
by ysth (Canon) on Nov 26, 2004 at 10:03 UTC
    That would be one way, but you need to change:
    my $x = Test->new(); my $dog = \$x; push @pack, $dog;
    to just:
    push @pack, Test->new();
      The reason this is suggested is because the new() returns a blessed reference, then you are creating a reference to said blessed reference, and then you are pushing that reference-to-a-reference onto your array. It's better to just push the blessed reference itself.
      And since we're nitpicking, your (the original poster's) use of @pack as a global variable is bad form:
      #!/usr/bin/perl use Dog; my @pack = create_dogs(15); sub create_dogs #of course, this should possibly be a method of Dog, b +ut whatever { my $num = shift; map Dog->new, 1 .. $num; # or 0, whichever makes you happy. }
Re: Tracking objects.
by Happy-the-monk (Canon) on Nov 26, 2004 at 10:28 UTC

    For one thing, how is perl to know what "Test" is?
    I don't see you using that module.

    for (my $i=0; $i != $_[0]; $i++) {

    You are definiing $i but not using it for a purpose other than iterating the loop itself.
    This C-like for loop could look like this in Perl:

    for ( 1 .. $_[0]; ) {

    Cheers, Sören

      This would have the additional benefit of not going berzerk on negative values for $_[0]...
Re: Tracking objects.
by rinceWind (Monsignor) on Nov 26, 2004 at 15:32 UTC
    How does one generate and track a bunch of objects?
    A lot depends on whether you have control of the construction of the objects, or whether you are merely using someone else's class. Do you want to keep a handle on them from the time they are constructed, to the time they are destructed? (Beware, keeping an extra reference may stop the objects from being DESTROYed, without explicit removal from @pack and/or Scalar::Util::weaken magic).

    If it is your class, you can always make the 'new' method save a pointer in an array somewhere; for someone else's code, you could always subclass and override new, like this:

    package Hound; use strict; use warnings; use base qw(Dog); our @pack; sub new { my $pkg = shift; my $obj = $pkg->SUPER::new(@_); push @pack,$obj; $obj; }
    If you are wanting to do this generically, you might want to override CORE::GLOBAL::bless, but this is not for the feint hearted. Look at my module Devel::Leak::Object for an example of this.

    --
    I'm Not Just Another Perl Hacker

Re: Tracking objects.
by Jasper (Chaplain) on Nov 26, 2004 at 13:47 UTC
    I think your way of having an array of objects is pretty reasonable. Any code I've ever written with multiple interacting objects had done just this, and then iterated over the array, doing what needs to be done. This tends to imply a common interface to each object (if they are from different classes), like (slightly facetious)  $obj->do_stuff(). do_stuff would change its position, check for physical interactions, change its physical state, you name it.

    Someone else commented on the for loop being better written as (0..$_[0]), and that's probably true, but the c-style loop with a more sensible conditional ($i < $_[0], say) is valid.
Re: Tracking objects.
by Anonymous Monk on Nov 26, 2004 at 20:30 UTC
    The problem to add all objects to a stack (your @pack array) is that this will break Object destruction, since you always will have a reference to any object in the @pack list. To avoid that you can use the module Hash::NoRef, where you can add values to this hash without count the references to this values, keeping the behavior of the garbage colection system.
    package Dog ; use Hash::NoRef ; use vars qw(%GHOST_TABLE) ; tie(%GHOST_TABLE , 'Hash::NoRef') ; my $GHOST_ID ; sub new { my $class = shift ; my $this = bless( {} , $class ) ; ++$GHOST_ID ; $GHOST_TABLE->{$GHOST_ID} = $this ; return $this } package main ; { my $obj = new Dog() ; print $GHOST_TABLE->{1} ; ## will show the object reference } print $GHOST_TABLE->{1} ; ## will show undef