Why doesn't a subclass inherit its parent constants?

So, I was going to do my own business at the Museum, and I thought it might be nice to use a constant in these places, where I use numbers to understand what these numbers mean or if they change later.

So, in the parent class, I added a standard use constant

package Parent; use constant { NO_LEVEL => 0, MY_LEVEL => 1, YOUR_LEVEL => 2, }; package Child; extends 'Parent'; #just to demonstrate that child can or cannot access the constant sub printMyLevel{ print MY_LEVEL; } 

but the child class does not know about the constants set in the parent! Doh!

I guess I need to do Elk magic to make it work correctly or something else. My search for this problem did not pull up any results = /

+6
source share
5 answers

Since constants are routines, and you can get inheritance by calling them as a method, the bit has already been covered to death, there is a different attitude to things.

If you know that you work in only one file, you can use lexical constants to combine packages:

 package Parent; our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL); *NO_LEVEL = \0; # this split declaration installs aliases to numbers *MY_LEVEL = \1; # into the lexicals. since numbers are constants *YOUR_LEVEL = \2; # to perl, the aliased names are also constants package Child; # just to demonstrate that anything below can access the constants sub printAll { print "$NO_LEVEL $MY_LEVEL $YOUR_LEVEL\n"; } Child->printAll; # 0 1 2 eval {$NO_LEVEL = 3} or print "error: $@ \n"; # error: Modification of a read-only value attempted at ... 

If you don't need perl for die when assigning a constant, our declaration gets a little easier (and maybe my ):

 our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL) = (0, 1, 2); 

You can return a permanent nature while still using a brief syntax with a little magic:

 my $constant = sub {Internals::SvREADONLY($_[$_], 1) for 0 .. $#_}; package Parent; $constant->(our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL) = (0, 1, 2)); package Child; # just to demonstrate that anything below can access the constants sub printAll { print "$NO_LEVEL $MY_LEVEL $YOUR_LEVEL\n"; # interpolates :) } Child->printAll; # 0 1 2 eval {$NO_LEVEL = 3} or print "error: $@ \n"; # error: Modification of a read-only value attempted at ... 

You can, of course, omit $constant coderef and embed magic:

 package Parent; Internals::SvREADONLY($_, 1) for our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL) = (0, 1, 2); 
+3
source

Constants are routines.

 { package Parent; use Moose; use namespace::autoclean; use constant { NO_LEVEL => 0, MY_LEVEL => 1, YOUR_LEVEL => 2, }; __PACKAGE__->meta->make_immutable; }; { package Child; use Moose; use namespace::autoclean; extends 'Parent'; sub printMyLevel { my $self = shift; my $class = ref $self; print $class->MY_LEVEL; } __PACKAGE__->meta->make_immutable; } package main; my $child = Child->new; $child->printMyLevel; 

Keep in mind that constants are routines with an empty prototype. perl uses this to embed them at compile time. However, the method ignores prototypes, and therefore the inherited constants accessed in this way will not be nested.

+10
source

This is actually mentioned in the documentation , if only in passing:

"Constants belong to the package in which they are defined. To refer to a constant defined in another package, specify the full name of the package, as in Some::Package::CONSTANT . Constants can be exported by modules and can also be called as a class or instance , i.e. as Some::Package->CONSTANT or as $obj->CONSTANT , where $obj is an instance of Some::Package . Subclasses can define their own constants to override them in their base class. "

+6
source

Name them as a method.

 sub printMyLevel{ my ( $self, ) = $_; print $self->MY_LEVEL; } 
+4
source

Inheritance affects method calls ( $x->m ), period.

+2
source

Source: https://habr.com/ru/post/899629/


All Articles