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

I am trying to use, in the base class, a class constant defined in a derived class. e.g.

in file Thingy.pm

package Thingy; sub new { my ($class, $line) = @_; my $thingy = {}; ... if ($line =~ m/$PATTERN/) { ... } bless $thingy, $class; } 1;

in file Rubber.pm

package Rubber; @ISA = qw(Thingy); use vars $PATTERN = q(...); 1;

and later in the main script

use Rubber; my $line = ...; my $thing = Rubber->new($line);

but I always get 'use of unitialised value in regex compilation...'

Trying $class::PATTERN doesn't work either.

What am I doing wrong - how do I reference the constant in derived classs Rubber from the method in base class Thingy?

Replies are listed 'Best First'.
Re: class constants in derived classes
by adrianh (Chancellor) on Apr 03, 2003 at 09:46 UTC

    If you want to override the pattern in each subclass of Thingy then the easiest thing to do is to use inheritance. Have a method that returns the pattern that you override in each subclass. Something like this:

    package Thingy; sub new { my ($class, $line) = @_; my $thingy = bless {}, $class; my $pattern = $thingy->pattern; ... if ($line =~ m/$pattern/) { ... } return $thingy; } sub pattern { die "subclass should override me" }; ... package Rubber; @ISA = qw(Thingy); sub pattern { q(...) };
      beautiful - exactly what I want.

      Spent most of the night reading the camel, the cookbook and the damian - finally found it in appendix A (p430) of the damian - package lexicals aren't visble, but a method returning them is - which means I need to defined a sub pattern {} in every derived class that redefines the class variable - which is a little messy.

      This whole question came about as a result of refactoring an existing class hierarchy, and removing lots of duplicated code in each derived class. And having made it all clean, now every class that redefines the pattern neeeds a method, thats exactly the same as the base and other derived class methods, that returns the pattern.

      Maybe I need a deep think. I dont want to use constructors in the derived class', and call SUPER::new, then put pattern into the blessed hash. Maybe the derived class' that redefine the pattern can have a sub _redefine_pattern, that the constructor in the base class calls - we should check that the derived class has the method first via an ->can() call?

      Or should I add @EXPORT = ($PATTERN); to the derived modules (evil in an OO module ;-) )

        This whole question came about as a result of refactoring an existing class hierarchy, and removing lots of duplicated code in each derived class. And having made it all clean, now every class that redefines the pattern neeeds a method, thats exactly the same as the base and other derived class methods, that returns the pattern.

        I have been a drinker of the OO Kool Aid for many years - but since these methods capture the difference between the classes it seems like an elegent solution to me ;-) Certainly more elegant than exporting a global. To-may-to, To-mah-to. I guess.

        If only some sub-classes redefine pattern just have the base class's pattern method return the default instead of throwing an exception. If you don't want to change the default, don't write a pattern method in the sub-class. I'm not quite sure from your description why you end up with more code?

Re: class constants in derived classes
by broquaint (Abbot) on Apr 03, 2003 at 08:40 UTC
    Your problem is that $PATTERN in new() is considered a package variable (as it hasn't been declared lexically) so new() is looking up $Thingy::PATTERN and, understandably, is not finding it. A possible solution would be to implement your derived class constructors like so
    { package Rubber; @ISA = qw( Thingy ); $PATTERN = q( ... ); sub new { local $Thingy::PATTERN = $PATTERN; $_[0]->SUPER::new(@_[1 .. $#_]); } }

    HTH

    _________
    broquaint

Re: class constants in derived classes
by Joost (Canon) on Apr 03, 2003 at 10:03 UTC
    Perl does not have class constants (or any other class data member) per se. It does have package scope variables, but those are not inherited.

    In fact the only thing you can inherit from a base class are the (class and object) methods. Even object data members are not automatically inherited - most of the time they're all mashed together in the underlying hashref. The OO features of Perl are quite primitive - though I do find the method calls quite enlightning and clear compared to other languages that try to hide things like references, $self / this etc.

    Now, as a solution to your problem I would propose to use a method that returns the pattern that you need. adrianh's solution above is a good example of how to do that. - For optimisation you'd might take a look at the qr construct in perlop.

    HTH.

    -- Joost downtime n. The period during which a system is error-free and immune from user input.
•Re: class constants in derived classes
by merlyn (Sage) on Apr 03, 2003 at 13:56 UTC
    Your use vars syntax is broken. The only thing use vars can do is permit a package variable to be spelled without the colons when the current package is the same as the package variable's package.
    use vars qw($PATTERN); $PATTERN = qr(...); ... ... if ($line =~ $PATTERN) { ... }
    Perhaps you were confusing it with our, which in fairly recent Perl versions, permits a "my"-style declaration, but accesses a package variable rather than a lexical variable.

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

      oh bugger - yes the example is wrong, but I do it right in the code I am trying to fix.