So I was going about my Moosey business and I thought hey might be nice to use a constant in these places where I'm using numbers, to make it clear what these numbers mean or in case they change later
So in the parent class I added the 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 is not aware of the constants set in the parent! doh!
I'm guessing I have to do some Moose magic to get this to work right, or something else entirely. My searching on this issue didnt pull up any results =/
A subclass inherits all the members (fields, methods, and nested classes) from its superclass. Constructors are not members, so they are not inherited by subclasses, but the constructor of the superclass can be invoked from the subclass.
Subclasses inherit public methods from the superclass that they extend, but they cannot access the private instance variables of the superclass directly and must use the public accessor and mutator methods.
We can create subclasses of a given class that will inherit all of the instance variables and methods of the given class (called the super class) using the keyword extends . An example can be seen in the classes defined below.
Inheritance concept is to inherit properties from one class to another but not vice versa. But since parent class reference variable points to sub class objects. So it is possible to access child class properties by parent class object if only the down casting is allowed or possible....
Constants are subroutines.
{
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 subroutines with an empty prototype. perl
takes advantage of this to inline them during compilation. However, method calls disregard prototypes, and therefore inheritable constants accessed this way would not be inlined.
This is actually mentioned in the documentation, if only in passing:
"Constants belong to the package they are defined in. To refer to a constant defined in another package, specify the full package name, as in
Some::Package::CONSTANT
. Constants may be exported by modules, and may also be called as either class or instance methods, that is, asSome::Package->CONSTANT
or as$obj->CONSTANT
where$obj
is an instance ofSome::Package
. Subclasses may define their own constants to override those in their base class."
Since the constants are subroutines and you can get inheritance by calling them as methods bit has been covered to death already, here is a different spin on things.
If you know you are only working in a single file, you can use lexical constants to bridge 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 to die when assigning to the constant, the our
declaration gets a bit simpler (and could be a my
):
our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL) = (0, 1, 2);
You can bring back the constant nature while still using the terse 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 the $constant
coderef and inline the magic:
package Parent;
Internals::SvREADONLY($_, 1)
for our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL) = (0, 1, 2);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With