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

NOTE: I'm using perl 5.00503 on Solaris 5.8 very unfortuantely.

I know I'm missing something really stupid easy, so at the risk of sounding like a complete moron, I'll ask anyways. That sort of thing doesn't intimidate me. Basically, I'm trying to do with Package variables what happens with subroutines. Its easier to explain in code:
package Obj; use strict; our $Name; sub new { my $proto = shift; my $class = ref $proto || $proto; my $self = bless {}, $class; return $self; } sub test { my $self = shift; print "$Name \n"; } package Test; use strict; our @ISA=("Obj"); $Name = 'Testing'; package main; my $t = new Test; $t->test;
As you probly already know this produces an error about $Name being undeclared. So I tried this:
#$Name = "Testing"; TO our $Name = "Testing";
Which results in printing nothing. So then I remember TheDamian's book, and the "SUPER::" package, so I figure if I _HAVE_ to I'll do this:
#$Name = "Testing"; TO $SUPER::Name = "Testing";
I get the same results as before. Nothing is printed. So I delve into perltoot, perltooc, perlbot, and perlobj which present similar but not exactly the same thing style examples. Confused and wondering if I've been dreaming for the past few years of perl development, I hardcore the package for a sanity check:
#$Name = "Testing"; TO $Obj::Name = "Testing";
This code actually works and produces the desired output. Leaving me completely Confused. Is "SUPER::" only for subroutine location? I want to abstract out the "Obj" class from the "Test" Class. Ideally, I'd like the the test() method in the the Obj class be able to use the current package's $Name. What is the best way to acheive this?

Update: My orignal code actually does what I want on perl 5.6.1 on my personal machine. Am I forced to kludge this to work with perl 5.00503?
-brad..

Replies are listed 'Best First'.
Re: Package Variables in Inheritance
by broquaint (Abbot) on Oct 31, 2003 at 19:40 UTC
    Unfortunately perl doesn't do data inheritance, it only does subroutine inheritance. This is because variables are looked up in a very simplistic manner - look in the immediate surrounding lexical pad and then in the current package's symbol table and then in any higher lexical pads. Whereas subroutines (for the most part) are looked up more dynamically - check the current package, check AUTOLOAD, check in parent classes (roughly).

    So, yes, SUPER:: is strictly for subroutines. Although you can get to the current package's variable, it will have to be symbolically e.g

    sub test { no strict 'refs'; print "name: ", ${"$_[0]::name"}, "\n"; } $foo::name = "I'm a foo"; $bar::name = "I'm a bar"; @foo::ISA = @bar::ISA = 'main'; foo->test(); bar->test(); __output__ name: I'm a foo name: I'm a bar
    HTH

    _________
    broquaint

Re: Package Variables in Inheritance
by tilly (Archbishop) on Oct 31, 2003 at 20:25 UTC
    What you want to have happen (searching your data hierarchy) only happens with method lookups. With direct function calls, you don't get that behaviour. That is, in your above example,
    Test->new(); # Calls Obj::new Test::new(); # Fails $Test::$foo; # Fails for the same reason that Test::new did
    The SUPER:: trick works by SUPER::AUTOLOAD catching method calls and redirecting it up the inheritance hierarchy.

    Therefore you will either have to arrange to be using method lookups (exactly like perrin suggested) or you will have to figure out the package that you want to look things up in and look stuff up dynamically on the fly using typeglobs etc.

    Of the two options, I would think that methods are a cleaner way to go. But if you want...

    sub test { my $self = shift; my $class = ref($self) || $self; local $Name; { no strict 'refs'; *Name = \${"$class\::Name"}; } print $Name; }
Re: Package Variables in Inheritance
by perrin (Chancellor) on Oct 31, 2003 at 19:52 UTC
    It's not clear what you're after here. If you want actual inheritable class data, you should use Class::Data::Inheritable. If you just want to access some globals in the parent class, you can fully qualify them as you did in your $Obj::Name example, but that's not inheritance. Your example using "our" is not inheritance either. It's just the same thing, with a lexically scoped alias for $Obj::Name. It only works because you have both packages in the same file.

    The "SUPER" keyword only works on method calls. The way you used it, it just gets treated as the literal name of a package.

      Cool. That makes me feel better. Basically, I know there are several ways to do this. The real code is a report writer. There are 3 variables I want to be able to change in a child class. Then I want to over load two function header() and footer() if necessary. Brain is fried, but basically, here's what I'm trying to accomplish.

      Base Class is the Report Writer. It doesn't care what its writing, it writes things. I want to inherit from it and change 3 variables, the sheetname, the header array (column names), and the fields hash (which is kinda cool, it knows how to extract each field from a generic hash which is used to generate 7 different reports). I'm lazy (this is why I love perl) and I wanted to basically do this:
      package Report::Writer::Test; use vars qw/@ISA/; @ISA=qw/Report::Writer/; $SheetName = "Test"; @HEADER = qw/I AM TESTING/; %Fields = ( I => sub { return uc $_[0]->{firscol} }, AM => 'secondcol', TESTING => 'PLACE HOLDER' );
      The end result, is based on my Report::Writer module, I wouldn't have to write anything else to make Report::Writer::Test work.

      broquaint's solution was what I was looking for. I'll investigate Class::Data::Inheritable to see if it does what I want it to do. Thank you for the suggestion.
      -brad..
Re: Package Variables in Inheritance
by hardburn (Abbot) on Oct 31, 2003 at 20:50 UTC

    Data you want to be inheirtable should go in the reference you are blessing (usually a hash). Use lexical variables (declared my at the top of your package) for private data.

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    : () { :|:& };:

    Note: All code is untested, unless otherwise stated

      Yes, I agree. This was more of a laziness thing than anything else. I have a lot of perl OO experience, just I had never attempted the package variable overloading before and was crossing my fingers that there'd be a way to do it. I understand why its not necessarily a good idea, but perhaps there are some cases where it could be useful (see my previous post). Maybe something like this:
      our $SheetName is overload;
      Maybe I'll look at doing something along those lines one day. I can't imagine it'd be too difficult. Or maybe something like C's extern, which says "this variable will be defined elsewhere" where elsewhere means a sub class of the current class. Uhm. I'm operating between Abstraction and Interfaces, and its confusing.

      Does anyone see any value in this?

      -brad..
        Use subs instead of data, so your example becomes:
        package Obj; use strict; sub name { undef } sub new { my $proto = shift; my $class = ref $proto || $proto; my $self = bless {}, $class; return $self; } sub test { my $self = shift; print $self->name, " \n"; } package Test; use strict; our @ISA=("Obj"); sub name { 'Testing' } package main; my $t = new Test; $t->test;
Re: Package Variables in Inheritance
by freddo411 (Chaplain) on Nov 01, 2003 at 01:05 UTC
    I haven't tried to understand your problem very deeply, but right off the bat I can tell you that perl 5.005 doesn't support our.

    our $foobar;

    try:

    use vars qw/ $foobar/;

    -------------------------------------
    Nothing is too wonderful to be true
    -- Michael Faraday