Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

OO-Perl Question: How Do I get a List of derived Classes for a Base Class?

by BluePerl (Novice)
on Mar 13, 2010 at 18:21 UTC ( #828461=perlquestion: print w/ replies, xml ) Need Help??
BluePerl has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I read a lot of documentation on OO-Perl. It looks great and I missed a detail for making a clean implementation: I try to get a list of derived classes for a base (super) class. Here is a simplified example:

use strict; use warnings; package Element; sub new { my $type = shift; my $self = {}; bless $self, $type; } package Circle; use vars qw(@ISA); @ISA = qw( Element ); package Square; use vars qw(@ISA); @ISA = qw( Element ); package Line; use vars qw(@ISA); @ISA = qw( Element ); package main; # seeking for a function like: # list_of_derived_classes ('Element'); # which returns -> 'Circle', 'Square', 'Line'
How can I implement the function list_of_derived_classes as noted in the example above?

A possible solution would be too, if the derived classes would register himself in the super class. But this solution shouldn't have code redundance. A good idea would be, if the super class contains the code for registering. This code should be called from the derived classes.

Comment on OO-Perl Question: How Do I get a List of derived Classes for a Base Class?
Download Code
Re: OO-Perl Question: How Do I get a List of derived Classes for a Base Class?
by Anonymous Monk on Mar 13, 2010 at 18:53 UTC
      Module::Pluggable is a wonderful module. I use it on a regular basis. But it does not do what the OP is looking for, at least in the general case.

      Module::Pluggable would not, for example, find the Circle, Square, and Line subclasses in the OP's code, as they are contained within the same source file.

      Module::Pluggable does its thing based on the module file names and their implied namespaces. It knows nothing about the actual inheritance relationships in the code. If you were to send it to find things under "Element", it would return packages found in the file Element/NotAChildClass.pm while missing an Element::Pentagon class that lived in the file SomewhereElse/Pentagon.pm.

Re: OO-Perl Question: How Do I get a List of derived Classes for a Base Class?
by almut (Canon) on Mar 13, 2010 at 18:53 UTC

    Not exactly what you're asking, but Devel::Symdump has (among other useful things) two methods inh_tree() and isa_tree() that might help.  It works by analyzing the symbol table for a set of packages (all those which are loaded at the time of the call).

    ... ... your code here ... package main; use Devel::Symdump; print Devel::Symdump->inh_tree();

    Output:

    Element Circle Line Square Exporter Carp

    (The presence of Exporter / Carp in the output is a side effect of the warnings pragma being loaded, which in turn loads Carp and Exporter as a dependency.)

Re: OO-Perl Question: How Do I get a List of derived Classes for a Base Class?
by CountZero (Bishop) on Mar 13, 2010 at 19:00 UTC
    Have a look at Class::MOP and more specifically Inheritance_Relationships from Class::MOP::Class.

    It has two methods that could be useful for you:

    $metaclass->subclasses
    This returns a list of all subclasses for this class, even indirect subclasses.
    $metaclass->direct_subclasses
    This returns a list of immediate subclasses for this class, which does not include indirect subclasses.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: OO-Perl Question: How Do I get a List of derived Classes for a Base Class?
by BrowserUk (Pope) on Mar 13, 2010 at 21:42 UTC
    How can I implement the function list_of_derived_classes

    What will you use this for?


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      I wrote a simple parser, which looks for comments inside SQL-Code. If it find a specific remark, the parser store data and generates some output for documentation. There are different types of comments which generates different type of documentation parts. The main idea is to generate a super class with the main methods an derive some class as an implementation for a specific comment type.

      This is no problem until here. In the main loop parse the sql-code and had to look, which derived object matches. The parser should try to match each derived object without write down each typename.

      Choosing this type of implementation, it will be easy to extend the solution by a new commenttype: Only a new derived class is needed.
        Choosing this type of implementation, it will be easy to extend the solution by a new commenttype: Only a new derived class is needed.

        You choose a derived class to instantiate, according to a comment in the data. That's fair enough, but it doesn't explain why you need to build a list of all possible derivable types? There is presumably a relationship between the value of the comment, and the name of the derived class to instantiate?

        All that knowing what is available achieves, is the ability to take a slightly earlier exit if you read a comment that requires a class that isn't available. But the additional complexity required to decide not to try and instantiate an instance of an unavailable class doesn't justify itself when simply making the attempt to instantiate the instance tells you the same information for free.

        Eg.

        my %derived = listOfDerivedClasses( 'Element' ); while( <SQL> ) { my( $type ) = m[...]; die "Derived type $type not available" unless exists $derived{ $ty +pe }; push @instances, $type->new(); }

        Versus:

        while( <SQL> ) { my( $type ) = m[...]; my $inst; eval{ $inst = $type->new(); 1 }; die "Derived type $type not available:'$@'" if $@; push @instances, $inst; }

        I guess my question is, does the extra complexity of providing introspection buy you something that is otherwise unavailable; or provide for it in some way that is sufficiently better to justify the cost?


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: OO-Perl Question: How Do I get a List of derived Classes for a Base Class?
by shmem (Canon) on Mar 13, 2010 at 22:34 UTC

    I never felt the need to do such, but here is how I would do it.

    Since every symbol table of packages your current package knows about is in the current package's symbol table, and since subclassing basically consists in including the base class in a packages's @ISA array and overriding some methods, I'd look at the current symbol table for packages it contains and see if the @ISA array of those packages contains the package looked for.

    Something like this:

    #!/usr/bin/perl -w use strict; package Bar; use base 'IO::Handle'; package Element; sub new { my $type = shift; my $self = {}; bless $self, $type; } package Circle; use vars qw(@ISA); @ISA = qw( Element ); package Square; use vars qw(@ISA); @ISA = qw( Element ); package Line; use vars qw(@ISA); @ISA = qw( Element ); package main; sub list_of_derived_classes { my $class = shift; my @pkg_keys; { no strict 'refs'; @pkg_keys = grep { /::$/ } keys %{__PACKAGE__.'::'}; } my @result; for (@pkg_keys) { no strict 'refs'; if (defined ${$_}{ISA}) { push @result, $_ if grep {/^$class$/} @{${$_}{ISA}}; } } s/::$// for @result; @result; } for my $class (qw(Element IO::Handle)) { print "$class\: ",join(', ', list_of_derived_classes($class)),$/; } __END__ Element: Circle, Line, Square IO::Handle: Bar

    Converting the symbol table lookups into a form which passes strict 'refs' is left as an excercise to the reader ;-)

Re: OO-Perl Question: How Do I get a List of derived Classes for a Base Class?
by WizardOfUz (Friar) on Mar 14, 2010 at 09:47 UTC

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (6)
As of 2014-09-19 00:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (129 votes), past polls