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

A little bit of an odd question. I'm experimenting with inheritance and I can get it to work as long as I set the variables in the instance of the child class since the self object that contains the variable will be passed to the parents function that I'm calling. IE the child module has the variable VERSION that I set in the new function to $self->{VERSION} = VERSION. The parent module has the method sub GetVersion() that prints the version of the module.

What I'm trying to figure out, is if there is any way to have the modules variable $VERSION accessible from a parent class without setting it in the instance? The only thing I can think of to do it is to have the parent include that module at the time I need the version but that kind seems like a hack.

Any other ideas?

Replies are listed 'Best First'.
Re: Perl Inheritance & module variables
by kyle (Abbot) on Sep 18, 2008 at 15:26 UTC

    One way would be for the child to override GetVersion(). Then a method in the parent can call $self->GetVersion() and get the child's version (if $self is actually an instance of the child).

    Another way might be through package variables, but I don't recommend that.

Re: Perl Inheritance & module variables
by gone2015 (Deacon) on Sep 18, 2008 at 16:30 UTC

    So, you have a module called Foo::Bar and objects of the class Foo::Bar, and you want to find the version of the module associated with the object, yes ? For example, while doing some superclass stuff ?

    Which would be something along the lines:

    package Foo::Bar ; ..... our $VERSION = "0.00" ; .....
    and somewhere you have:
    my $obj = new Foo::Bar (...) ;
    and somewhere else you want to find the $VERSION associated with $obj ?

    Suppose you had Foo/

    package Foo::Bar ; use strict ; use warnings ; our $VERSION = "1.01" ; use base qw(Foo); sub new { return bless [], shift ; } ; 1 ;
    package Foo ; use strict ; use warnings ; our $VERSION = "0.11" ; sub version { my ($self) = @_ ; no strict 'refs' ; # NB: seatbelt off. return ${ref($self)."::VERSION"} ; # "Symbolic Reference" } ; 1 ;
    use strict ; use warnings ; use Foo::Bar ; my $obj = new Foo::Bar ; print $obj->version(), "\n" ;
    should print:
    which may have been what you had in mind.

    It may also be what kyle just recommended NOT to do ?

      Well that does what I want but I really hate having to turn off the strict refs... I think I would prefer to just copy the data into the instance and deal it with that way unless there is a lot of data i need to copy or its time sensitive. Unless there is a better way of doing it, I think I might just keep that in my back pocket for when I really do need it.

      Thanks a bunch

        Wishing to maintain "strict refs purity" is entirely commendable :-)

        For completeness, however, I'll point out that the 'no strict'-ness is scoped within the current block. So the unpleasantness is contained. In the code I gave the the nastiness was enclosed in a subroutine. If it's necessary to do this in 'open code' you can always:

        { no strict 'refs' ; .... # unspeakable stuff redacted } ;
        to avoid contagion

        Anyway, I think that with a small penance, in the form, say, of an explanatory comment, one can forgive oneself this particular sin -- provided it doesn't become a habit :-)

Re: Perl Inheritance & module variables
by brian_d_foy (Abbot) on Sep 20, 2008 at 19:41 UTC

    You're really asking how to write accessor methods. You call a method and you get the value of some property. You want to write methods that ask the question you want answered.

    Here are two class, Parent and Child. The Child class inherits from Parent. Inside each class there is a VERSION method that returns the value of the $VERSION in that package. In neither case is $VERSION part of the object. They are class data.

    package Parent; our $VERSION = 1.23; sub VERSION { $VERSION } sub child_version { $_[0]->VERSION } package Child; use base qw(Parent); our $VERSION = 5.43; sub VERSION { $VERSION } sub new { bless {}, $_[0]; } sub parent_version { $_[0]->SUPER::VERSION }

    Those VERSION methods take care of answering the version question for each package as long as I call them directly as class methods:

    print "Parent version is ", Parent->VERSION, "\n"; # 1.23 print "Child version is ", Child->VERSION, "\n"; # 5.43

    But now I want to do that from a Child object. That's where the child_version and parent_version methods come in. Once I have the $child object, in parent_version I can get its parent version by calling its SUPER class. The SUPER is a virtual class that is the parent class of the one it is compiled in (Child in this case).

    my $child = Child->new; print "Child version: ", $child->VERSION, "\n"; # 5.43 print "Parent version: ", $child->parent_version, "\n"; # 1.23

    The VERSION and parent_version methods in Child take care of most everything you need. Where you're getting confused, I think, is how the Parent fits in to this. More on that in a moment. You can add a child_version method to Parent. It just takes the first thing on the argument list and calls VERSION on it. When I call child_version on the $child object, Perl doesn't find the child_version in Child so it looks in its superclass and finds it in Parent:

    print "Child version: ", $child->child_version, "\n"; # 5.43

    However, one of the points of inheritance is that you shouldn't need this two-way communication. You don't think about the parent class having part of it and the child class having another part. In this case, the child_version method is just the same thing as Child's VERSION:

    print "Child version: ", $child->VERSION, "\n"; # 5.43 print "Child version: ", $child->child_version, "\n"; # 5.43

    In Parent's child_version, it takes the first thing on the argument list, which is the $child object. That's how Parent accesses anything it needs to know in Child: just ask the child object that you got as the first argument.

    brian d foy <>
    Subscribe to The Perl Review
Re: Perl Inheritance & module variables
by Anonymous Monk on Sep 19, 2008 at 09:26 UTC
    C:\>perl -MCGI -e"die CGI->VERSION" 3.38 at -e line 1. C:\>perl -MCarp -e"die Carp->VERSION" 1.04 at -e line 1. C:\>perl -Mstrict -e"die strict->VERSION" 1.03 at -e line 1. C:\>perldoc UNIVERSAL ... "VERSION ( [ REQUIRE ] )" "VERSION" will return the value of the variable $VERSION in the package the object is blessed into. If "REQUIRE" is given then it will do a comparison and die if the package version is not greate +r than or equal to "REQUIRE". "VERSION" can be called as either a class (static) method, an obj +ect method or a function.

      I saw that but I haven't been able to figure out how UNIVERSAL works. The reason I ask is because VERSION isn't the only variable I want. I would like to define several constants that UNIVERSAL doesn't appear to be able to grab except for VERSION. If it can, please send me docs that describe it.