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

I've written some Perl that I'm a little unsure of and wanted to bounce it of the Perl Monks.

The problem: I need to create member variable that is an array of objects that can be accessed by various other classes that will expect a particular type of object, in the example a URL object.

To illustrate I've created a couple of simple classes and a script to build a couple of URL objects, popular an array and then iterate the array printing out the results.

My question: Is this the best way to manage data in Perl OOP?

#!/usr/bin/perl -w package URL; use strict; use Data::Dumper; sub new { my $class = shift; my $self = {}; $self = bless($self, $class); return $self; } sub load { my $self = shift; my %data = %{$_[0]}; $self->url($data{url}); $self->urlid($data{urlid}); } sub url { my $self = shift; if (@_) { $self->{url} = shift; } return $self->{url}; } sub urlid { my $self = shift; if (@_) { $self->{urlid} = shift; } return $self->{urlid}; } 1


#!/usr/bin/perl -w package Tester; use strict; use URL; use Data::Dumper; sub new { my $class = shift; my $self = {}; $self = bless($self, $class); return $self; } sub add { my $self = shift; my @urls; if ($self->{urls}) { @urls = @{$self->{urls}}; } else { @urls = (); } my $url = ${$_[0]}; push(@urls, $url); $self->{urls} = \@urls; } sub next { my $self = shift; my @urls = @{$self->{urls}}; if (!@urls) { return undef; } my $url = pop(@urls); $self->{urls} = \@urls; return $url; } 1


#!/usr/bin/perl -w use strict; use Tester; use URL; use Data::Dumper; my $test = Tester->new(); my $url = URL->new(); my %hash = ('urlid'=>2,'url'=>'http://www.perlmonks.org'); $url->load(\%hash); $test->add(\$url); my %hash2 = ('urlid'=>3,'url'=>'http://www.ire.org'); my $url2 = URL->new(); $url2->load(\%hash2); $test->add(\$url2); while (my $u = $test->next()) { printf "URL ID: %d URL: %s\n", $u->urlid, $u->url; }

Replies are listed 'Best First'.
Re: How to store objects as arrays in other objects
by almut (Canon) on Dec 07, 2008 at 21:28 UTC

    You're doing quite a lot of copying, which - it seems - is mostly unnecessary. For example, your next() method

    sub next { my $self = shift; my @urls = @{$self->{urls}}; if (!@urls) { return undef; } my $url = pop(@urls); $self->{urls} = \@urls; return $url; }

    could also be written as

    sub next { my $self = shift; return pop @{$self->{urls}}; }

    which should be functionally equivalent...  Similarly add().

      Yes, that code looked junkie, but I wasn't sure how to clean it up.

      Thanks.
Re: How to store objects as arrays in other objects
by kennethk (Abbot) on Dec 07, 2008 at 21:27 UTC

    First, best is subjective, especially in perl.

    One popular framework for OOP in perl is Moose. It will handle basic functional stuff so you can concentrate on structure more than ground-level functions. Also see Moose::Intro and Moose::Cookbook for the how-to. Based on the apparent simplicity of what you want to do, it would seem a good choice.

    In terms of what you have, I would avoid using explicit hash references to pass data to your objects. If an object has sufficiently complex structure to justify that, you really ought to be adding children to handle the data and appropriate accessors there. This follows the OOP ideal that all objects without children should be simple. The extra complexity is demonstrated by the fact that you need to pass a hash reference to your set routine.

Re: How to store objects as arrays in other objects
by spmlingam (Scribe) on Dec 08, 2008 at 11:42 UTC
    In the package URL, you can use Class::Struct, instead of defining functions url and urlid.
Re: How to store objects as arrays in other objects
by otto (Beadle) on Dec 08, 2008 at 05:31 UTC
    Suggestion - look at Moose on cpan instead of rolling your own.