Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris

Object loading at runtime

by benrwebb (Scribe)
on Jun 16, 2005 at 20:18 UTC ( #467426=perlquestion: print w/replies, xml ) Need Help??

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

Ok, Here is one of those elusive "best way" questions...

I have one Class with many, many children. In all cases I will need to create an object of one of those child classes, but I won't know which one until runtime. Is there an idomatic way to do this? Am I going to have to eval "use ..." and suffer the consequences?


Replies are listed 'Best First'.
Re: Object loading at runtime
by Transient (Hermit) on Jun 16, 2005 at 20:21 UTC
    One way ( this was discussed in the CB recently ) is to use a factory, e.g.:
    #!/usr/bin/perl use warnings; use strict; package Class; sub new { bless {}, $_[0] }; 1; package Class::SubclassA; sub new { bless {}, $_[0]; }; 1; package Class::SubclassB; sub new { return bless {}, $_[0]; }; 1; package ClassFactory; my %creation_hash = ( SubclassA => sub { Class::SubclassA->new() }, SubclassB => sub { Class::SubclassB->new() } ); sub create { shift; print $creation_hash{$_[0]}, "\n"; return $creation_hash{$_[0]}->(); } 1; package main; my $a = ClassFactory->create( "SubclassA" ); my $b = ClassFactory->create( "SubclassB" ); print $a, "\n"; print $b, "\n";
      Don't hardcode the daughterclass names, or else you won't be able to subclass the factory class. Instead, call a method that returns the daughterclass name:
      sub TypeA { return "Class::SubclassA" } sub TypeB { return "Class::SubclassB" } sub create { my $class = shift; if (shift eq "B") { return $class->TypeB->new(@_); } else { return $class->TypeA->new(@_); } }

      -- Randal L. Schwartz, Perl hacker
      Be sure to read my standard disclaimer if this is a reply.

Re: Object loading at runtime
by mugwumpjism (Hermit) on Jun 16, 2005 at 21:31 UTC

    There isn't much of a penalty on eval STRING when it's a simple statement like use. Not compared to the time it takes to load the module! :)

    You can always use require, but you first have to perform a transform on the module name (this is a design bug which is tidied in Perl 6):

    my $module = "Some::Class"; $module =~ s{::}{/}g; $module .= ".pm"; require $module;

    There will be a cargo cult disapproving of require, be sure to poke your tongue out at them, laugh and ask them why until they say "'coz" :-).

    You can also look at Class::Tangram::Generator for an example of code that defers loading of modules until objects of the relevant type are created, using several different mechanisms.

    $h=$ENV{HOME};my@q=split/\n\n/,`cat $h/.quotes`;$s="$h/." ."signature";$t=`cat $s`;print$t,"\n",$q[rand($#q)],"\n";
Re: Object loading at runtime
by adrianh (Chancellor) on Jun 16, 2005 at 20:59 UTC
    Am I going to have to eval "use ..." and suffer the consequences?

    Pretty much. If you don't want to load the modules until runtime then you're going to have to use one of use, require or do. There are some CPAN modules like Class::Factory that wrap up most of the hard work for you .

Re: Object loading at runtime
by davidrw (Prior) on Jun 16, 2005 at 20:56 UTC
    You can also use Class::Runtime
    my $s = 'Dog'; my $class = 'My::Pets::' $s ; use Class::Runtime; my $cl = Class::Runtime->new( class=> $class); $cl->load unless $cl->isLoaded; my $obj = $class->new;

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://467426]
Approved by wazoox
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (9)
As of 2020-01-27 21:16 GMT
Find Nodes?
    Voting Booth?