perl-modperl mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Tuomo Salo <Tuomo.S...@cybercom.com>
Subject Re: Is it me or is mod_perl extremely dangerous?
Date Wed, 07 Dec 2011 11:32:01 GMT
On Tue, Dec 06, 2011 at 03:55:54PM -0500, Desilets, Alain wrote:
> package MyClass;
> 
> my $class_level_attribute;
> 
> sub new {
> 	my ($class) = @_;
> 	$self->{instance_level_attribute} = undef;
> 	bless $self, $class;
> 	return $self;
> }
> ------------
> 
> The idea here is to emulate the concept of "static" (in Java or C++ parlance) class level
attributes, i.e., attributes which are tied to the the class itself as opposed to instances
of it.

Please do not do that.

When you use a "my" variable outside a subroutine, you create a variable
that is completely invisible from anywhere outside of that file. This 
violates some core principles of object oriented programming, and perl
itself:

  * Do not attempt to verify the type of $self. (Tenet #1 from "man perlbot")
  * The object is the namespace. (#6, same source)
  * Don't assume you know the home package of a method (#9)
  * There's more than one way to do it (Perl motto from "man perl")

The first one is violated, since you have a variable that can only be
seen in your file, and therefore only one type of objects will ever
be able to see it. Same goes for the third: any method accessing the
variable is by necessity defined in that very package. 
Violating the second one is the cause for the other two.

The final one is violated, since if someone has decided to do it,
there is really no way around it.

A demonstration follows.


This is the file MyClass.pm, let's say it is downloaded from CPAN. 
It contains a "my" variable at the package level. It also uses the 
variable. (Kind of obvious, since nobody else can see it.)

--------------
package MyClass;

my $class_level_attribute = "I Am MyClass";

sub new { my ($class) = @_; bless {}, $class; }
sub output { 
    print "My type is @{[ref $_[0]]}";
    print "The attribute is '$class_level_attribute'"; 
}
-------------

Now I really like the way MyClass works, but I would like to change just the
bit that is in the variable $class_level_attribute. So I create the file
SubClass.pm:

-------------
package SubClass;

use base MyClass;

my $class_level_attribute = "I want to be SubClass";
$::MyClass::class_level_attribute = 
"I want to be SubClass so much that I am ready to break class boundaries";
-------------

Then I'll try to run it by creating demo.pl

-------------
#!/usr/bin/perl -Twl
use strict;
use lib ".";

use SubClass;

my $object = new SubClass();
$object->output();
-------------

..but I won't be happy:

-------------
$ chmod +x demo.pl; ./demo.pl
My type is SubClass
The attribute is 'I Am MyClass'
-------------


Because I am not in control of MyClass.pm, I cannot make changes to that
file. If I do, my software will break whenever MyClass.pm is updated.

My other option is to override every subroutine that uses the class level
attribute. This may also break when the package is updated so that a new
subroutine starts to access the attribute.

My final option is to copy all functionality from the file to some
other file; that is, not to use MyClass after all. This is the only
way I can get the functionality I want. I won't be automatically 
benefiting from any updates to MyClass, but that is the price I have to pay.


The correct way to use the scopes for variables is (in my opinion):

- Explicitly global variables ($::Package::variable) in the package's own
  namespace for "final" variables (defaults names of existing instance 
  variables, for example) and anything that you absolutely have to save 
  to future invocations.
- Accessors for any instance variables ($object->variable()).
  Never access an instance variable directly, even if you know the
  structure of the object.
- Lexical variables ("my @args" inside a sub) for everything else,
  and finally:
- Argument passing ($object->method($variable)) for showing your lexicals
  to other subs.

If you do it this way, then easy things are easy, and hard things are possible.

(bonus: if, in addition, you never "use Exporter" to export anything, 
 you'll also get code where every variable name and function call is 
 easily traced back to its definition, even without special tools.)

  -Tuomo

Mime
View raw message