The @ISA
variable is a package variable that is used by all classes to indicate the class's parent (or parents). While this variable can be safely read to learn a class's inheritence inheritance hierarchy, it must not be modified at runtime [Conway 052005].
Noncompliant Code Example (@ISA
)
...
Code Block | ||||
---|---|---|---|---|
| ||||
{ package Base; sub new { my $class = shift; my $self = {}; # no parent bless $self, $class; print "new Base\n"; return $self; }; sub base_value {return 1;} } { package Derived; our @ISA = qw(Base); # establishes inheritenceinheritance sub new { my $class = shift; my $self = $class->SUPER::new(@_); # relies on established inheritenceinheritance print "new Derived\n"; return $self; }; sub derived_value {return 2;} } BEGIN { my $derived = Derived->new(); my $b = $derived->base_value(); my $d = $derived->derived_value(); print "base_value = $d$b\n"; print "derived_value = $d\n"; } |
When the code is run, we get a program error:
...
This error occurs because the BEGIN
block is evaluated at the beginning of runtime, before the @ISA
statement can be evaluated. ThereforeConsequently, when the Derived::new()
constructor is invoked, the Derived
class has an empty parents list and therefore fails to invoke Base::new()
.
Compliant Solution (
...
parent
)
This compliant solution uses the base
parent
module rather than directly modifying the @ISA
variable.
Code Block | ||||
---|---|---|---|---|
| ||||
# ... package Base is unchanged { package Derived; use baseparent qw(Base); sub new { my $class = shift; my $self = $class->SUPER::new(@_); # relies on established inheritenceinheritance print "new Derived\n"; return $self; }; sub derived_value {return 2;} } # ... The rest of the code is unchanged |
The base
parent
module establishes the inheritence inheritance hierarchy at parse time, before any runtime code, including the BEGIN
block, is evaluated. Therefore, when When the Derived::new()
constructor is invoked, Perl knows that Derived
is an instance of Base
, and the program produces the correct output:
Code Block |
---|
new Base new Derived derivedbase_value = 21 basederived_value = 1 2 |
Risk Assessment
Modifying class inheritence inheritance at runtime can introduce subtle bugs , and is usually a sign of poor design.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
OBJ00OOP00-PL | lowLow | unlikelyUnlikely | lowLow | P3 | L1L3 |
Automated Detection
Tool | Diagnostic |
---|---|
Perl::Critic | ClassHierarchies::ProhibitExplicitISA |
Bibliography
...
2005] |
...
"Inheritance," p. 360 | |
[CPAN] | Maischein, Max, parent |
[CPAN] | Shank, Elliot, Perl-Critic-1.116 ClassHierarchies::ProhibitExplicitISA |
...