Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Autocreating Classes

by water (Deacon)
on Oct 07, 2006 at 10:23 UTC ( [id://576817]=perlquestion: print w/replies, xml ) Need Help??

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

Hi -- I have a set of classes like this:
package A; # much base code which Does The Right Thing based on subclass type # thru ref($self) inspection 1; package B1; use base(qw(A)); # no code here 1; package B2; use base(qw(A)); # no code here 1; package B3; use base(qw(A)); # no code here 1; etc
That is, I set up a bunch of superthin subclasses of a base class -- they only differ between themselves in the class name.

Is there a way to dynamically generate the B1 ... Bn classes on the fly at execution, vs. creating them in B1.pm, B2.pm, etc. ?

water

Replies are listed 'Best First'.
Re: Autocreating Classes
by Joost (Canon) on Oct 07, 2006 at 12:18 UTC
    There is not really such thing as creating a package: namespaces are just autovivicated as soon as you assign something to a glob (i.e. create a global, sub, filehandle etc) in that namespace. To nearly all intents and purposes an empty namespace is a non-existing namespace.

    Since the only thing you're doing with the created package is setting its inheritance chain in @Package::ISA, you can do that directly:

    sub inherit_from_A { my $package_name = shift; no strict 'refs'; @{"${package_name}::ISA"} = qw(A); } # create class B1.. inherit_from_A('B1');
Re: Autocreating Classes
by gellyfish (Monsignor) on Oct 07, 2006 at 10:42 UTC
Re: Autocreating Classes
by stvn (Monsignor) on Oct 07, 2006 at 13:26 UTC

    If you need to generate these classes dynamically at runtime, then you could use the technique Joost suggested. However, if you have a fixed set of classes which you know at compile time, and are basically just looking to save your wrists from having to type things over and over, then you could use Module::Compile::TT to just expand the code you need at module load time (actually pre compile-time phase).

    package A; # ... code here use tt ( subclasses => [ map { 'B' . $_ } 1 .. 100 ] ); [% FOREACH subclass IN subclasses %] package [% subclass %]; our @ISA = qw(A); [% END %] no tt;
    There is always more than one way to do it ;)

    -stvn
Re: Autocreating Classes
by fenLisesi (Priest) on Oct 07, 2006 at 12:46 UTC
    eval came to my mind (I hope I am not totally missing the point here)

    StaticMammal.pm (The equivalent of your A):

    #!/usr/bin/perl -wT package StaticMammal; use strict; use warnings; sub new { my ($class) = @_; my $new_critter = bless {}, $class; return $new_critter; } sub walk { my ($self) = @_; print "A " . ref( $self ) . " walks " . $self->walks_how() . "\n"; return; } sub talk { my ($self) = @_; print "A " . ref( $self ) . " says " . $self->talks_how() . "\n"; return; } sub walks_how { return q(ponderously); } sub talks_how { return q(Grrr); } 1; __END__
    DynamicMammals.pm (The middleman that generates the equivalent of your Bn):
    #!/usr/bin/perl -wT package DynamicMammals; use strict; use warnings; use lib '.'; my %style_of = ( Cat => { talks => q(meow), walks => q(in beauty, like the night), }, Dog => { talks => q(woof), }, FrankenMammal => { ## empty hash }, ); my $package_str = q(); foreach my $mammal (keys %style_of) { $package_str .= qq( package Dynamic$mammal; use base qw(StaticMammal); ); my $action_href = $style_of{ $mammal }; foreach my $action (keys %$action_href) { $package_str .= sprintf q( sub %s_how { return q(%s); } ), $action, $action_href->{ $action}; } } eval $package_str; if (my $msg = $@) { die "Eval error: $msg\nwhile trying to eval:\n$package_str"; } 1; __END__
    Something that calls the equivalent of your Bn:
    #!/usr/bin/perl -wT use strict; use warnings; use lib '.'; use DynamicMammals; my $felix = DynamicCat->new(); my $spot = DynamicDog->new(); my $thing = DynamicFrankenMammal->new(); foreach my $critter ($felix, $spot, $thing) { $critter->walk(); $critter->talk(); } __END__
Re: Autocreating Classes
by Tanktalus (Canon) on Oct 07, 2006 at 16:11 UTC

    Lots of great ways to do it - but this smells of an XY Problem to me. As in, why does package A inspect $self? I can imagine a few cases where this may be desirable (especially with dynamic subclasses - subclasses where the name is part of the data), although even then it's kinda suspect (just put the name in the $self hash).

    In general, inheritance is done by simply putting overridable actions in their own subs, and then letting each package override the appropriate methods in the appropriate ways. No introspection required. Of course, you don't need to put them in separate files, either, but that's up to you.

Re: Autocreating Classes
by chromatic (Archbishop) on Oct 07, 2006 at 19:53 UTC

    Your comment says:

    # much base code which Does The Right Thing based on subclass type # thru ref($self) inspection

    I've never needed to do this in normal code. What are you doing that normal polymorphism is not enough?

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://576817]
Approved by GrandFather
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (6)
As of 2024-04-19 06:15 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found