Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing class variables in inherited function?

I'm trying to create child classes in Perl that inherit class functions from a single parent. I got it to partially work, using the object method syntax Child->inheritedMethod() to call inherited functions outside the child, and my $class=shift; $class->inheritedMethod(); inside the child class, as described here.

However, for inherited methods, it seems control is passed to parent class, and the method is run in the parent scope with the parent variables. For example, this is in the Parent class:

our $VERSION = 0.11;
our $NICKNAME = "Parent Base";
sub version{ $VERSION }
sub whoami{ $NICKNAME }
sub whereami{
  my $class = shift;
  print "should be printing whereami right now...\n";
  print "## In ",(caller(1))[3]," of ",$class->whoami," ",$class->version," in ",__PACKAGE__,"\n"; 
}

Each child class declares its own $VERSION and $NICKNAME, which I hoped would be accessed in place of the parent variables. But when I call whereami from the child, it gives ## Child::Method of Parent Base 0.11 in Parent.

Questions:

  • Is there a way around this? Some other module I should use like Moo(se)? Export all the methods instead of inheritance, which I hear shouldn't be done (polluting the namespace, not a problem here)?

  • Would this still be an issue using objects and object attributes/variables? I'm trying to avoid it due to my team's aversion to object-oriented.

  • Is this how inheritance usually works, or just Perl? I thought the method would be called within the scope of the child class, not passed to the parent.
like image 797
undefinedvariable Avatar asked Mar 01 '26 05:03

undefinedvariable


1 Answers

The problem is that the method accesses the variable from the lexical scope where it was declared, i.e. the parent class. Class variables are therefore not the same thing as class attributes.

You can access the correct variable by fully qualifying its name (not possible under strict refs:

#!/usr/bin/perl
use warnings;
use strict;

{   package Parent;
    our $package = 'Parent';

    sub get_package {
        my $class = shift;
        {   no strict 'refs';
            return (caller(0))[3], $class, ${"$class\::package"}
        }
    }
}

{   package Son;
    use parent 'Parent';
    our $package = 'Son';
}

print join ' ', 'Son'->get_package, "\n";
print join ' ', 'Parent'->get_package, "\n";

In Moo*, you can use Moo*X::ClassAttribute:

#!/usr/bin/perl
use warnings;
use strict;

{   package Parent;
    use Moo;
    use MooX::ClassAttribute;
    class_has package => (is => 'ro',
                          default => 'Parent');

    sub get_package {
        my $class = shift;
        return $class->package;
    }
}

{   package Son;
    use Moo;
    use MooX::ClassAttribute;
    extends 'Parent';
    class_has package => (is => 'ro',
                          default => 'Son');
}

print 'Parent'->get_package, "\n";
print 'Son'->get_package, "\n";

Note that MooX::ClassAttribute says

Overriding class attributes and their accessors in subclasses is not yet supported.

Unlike in Moose, you can't use the class_has '+package' => (default => 'Son'); syntax for overriding.

like image 108
choroba Avatar answered Mar 03 '26 19:03

choroba



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!