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