Perl provides no mechanism to hide variables or functions. Although it provides mechanisms such as my() that limit the scope of variables, it does nothing to prevent code from accessing any variable or method that is available and dereferenceable from its current scope.

By convention, packages may indicate that a method or variable is not to be used outside the class by prefixing the method or variable name with an underscore (_) [Conway 2005]. Perl provides no inherent enforcement of this convention; however, it is followed by many modules in CPAN and other developers. This convention must not be violated.

Noncompliant Code Example

This noncompliant code example provides a Car package that registers cars and keeps track of all cars that it creates.

{
  package Car;
 
  my %_all_cars;
 
  sub new {
    my ($class, $type) = @_;
    my $self = {type=>$type};
    bless $self, $class;
    $_all_cars{$self} = 1;
    return $self;
  };
 
  sub DESTROY {
    delete $_all_cars{shift()};
  };
 
  sub type {
    my $self = shift;
    return $$self{type};
  }
 
  sub _get_all_cars {
    return %_all_cars;
  }
}


my $mine = Car->new("Transam");
my $type = $mine->type();
print "I drive a $type.\n";
my $yours = Car->new("Corvette");
$type = $yours->type();
print "You drive a $type.\n";

my %cars = Car::_get_all_cars();
my @all = keys( %cars);
my $count = $#all + 1;
print "There are $count cars on the road.\n";

This program behaves as expected, correctly reporting 2 cars on the road. However, it clearly violates encapsulation, because the _get_all_cars() method is considered private within the Car class.

Compliant Solution

This compliant solution adds a public method and invokes it instead of any private method.

{
  package Car;

  my %_all_cars;

  sub count_cars {
    my @all = keys( %_all_cars);
    return 1 + $#all;
  }

  # ... other methods of Car
}

# ...
my $count = Car::count_cars();
print "There are $count cars on the road.\n";

Exceptions

OOP31:EX0: A class may access private subroutines in classes it is inherited from.

OOP31:EX1: This rule does not apply to classes or modules that do not obey this convention. For instance, the POSIX package provides an API to the system calls endorsed by the POSIX standard. Many of these calls begin with _ but are not meant to be private.

Risk Assessment

Using deprecated or obsolete classes or methods in program code can lead to erroneous behavior.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

OOP31-PL

Medium

Probable

Medium

P8

L2

Automated Detection

Tool

Diagnostic

Perl::Critic

 

Subroutines::ProtectPrivateSubs

Variables::ProtectPrivateVars

Bibliography

 


4 Comments

  1. Anonymous

    The destructor is buggy. First, the method should be named DESTROY to be eligible for automatic invocation. Then, $hash{shift} accesses the element called shift, but doesn't execute the built-in function of the same name. The code

        perl -Mstrict -Mwarnings -E'my %hash = ("foo"=>1, "shift"=>1); sub del{delete $hash{shift}} del("foo"); say for keys %hash'

    prints only foo (i.e. the "shift" element was deleted). To execute the function, do $hash{+shift} or $hash{shift()}. If a bareword appears in a hash subscript, it is used as a string. To force the interpretation as an expression, it has to be made an invalid bareword.

  2. Anonymous

    The POSIX link should probably be version agnostic link ( ordered from most preferred to least preferred )

    If you want a truly authoritative link it would be to http://perl5.git.perl.org/perl.git/blob/HEAD:/ext/POSIX/lib/POSIX.pod

     

    Since (I think) that core is upstream, it should probably be http://perldoc.perl.org/POSIX.html

    It should definitely not specify any one person http://perl5.git.perl.org/perl.git/history/HEAD:/ext/POSIX.

    If it did, it should specify "Wall, Larry" (I think) http://perl5.git.perl.org/perl.git/commit/463ee0b2acbd047c27e8b5393cdd8398881824c5

    (It is difficult to determine who was responsible for any given change back in those days)

    1. I updated the POSIX link to point to perldoc.perl.org.