bramble has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to understand why the way shown below is not a great way to deal with class variables, but still not getting it.

As an example, a shoe store, with Shoe and Boot classes. First, the Shoe class:

### In Shoe.pm package Shoe; use strict; use warnings; # Shoes with holes in their soles. my $num_holey = 0; sub new { my $class = shift; my $self = {}; # ... bless $self, $class; return $self; } # Instance method that happens to access a class variable. sub wear_out_sole { my $self = shift; $num_holey++; print "Sole on this shoe has been worn out.\n"; Shoe->how_many_holey(); } # Class methods. sub how_many_holey { my $class = shift; print "Currently, there are $num_holey holey shoes ($class).\n"; } sub incr_num_holey { my $class = shift; $num_holey++; } 1;

The Boot class:

### In Boot.pm package Boot; use base qw( Shoe ); use strict; use warnings; # Boots are like Shoes, but have a heel. # (Heel stuff not shown, for brevity.) sub new { my $class = shift; my $self = $class->SUPER::new(); # ... return $self; } # Instance method that has to deal with a class variable. sub wear_out_sole { my $self = shift; Shoe->incr_num_holey(); print "Sole on this BOOT has been worn out.\n"; Shoe->how_many_holey(); } 1;

And a script to use them:

#!/usr/bin/env perl use strict; use warnings; use Boot; my $s = Shoe->new(); $s->wear_out_sole(); my $b = Boot->new(); $b->wear_out_sole(); my $b2 = Boot->new(); $b2->wear_out_sole();

Everything seems to work fine. Yet, in perltoot, it says "It turns out that this {using file scope lexicals for class variables} is not really a good way to go about handling class data. A good scalable rule is that you must never reference class data directly from an object method". And I'm still not getting it. Why not directly access that class data?

A Boot is a Shoe, but should Boot be dealing with Shoe's $num_holey in some different way than shown above? I guess what I'm really asking is, what's the proper relationship between a subclass and its superclass's class data?

Replies are listed 'Best First'.
Re: Still not getting it: hashref OO class variables
by samtregar (Abbot) on Feb 14, 2008 at 23:54 UTC
    Referencing class data in an object method directly makes it hard to cleanly override the object method in a sub-class. How would you write an overridden wear_out_sole()? You'd have to access $num_holey, but can't because it's in a separate package scope. You solved this already in your class with incr_num_holey(), which is what the Fine Manual is trying to suggest.

    All that aside, I think you'll find that it's pretty unusual to use class data in a real OO system. In cases where you've really got some kind of class-wide data I'd rather see that data modeled as an object of its own and give each object that needs it a reference to the object. This is a common pattern for configuration data, for example, which is also a common (poor) use of class data.

    Another example: I've created in-memory caches in some of my modules using class data. These days I'd use something like CHI instead and give each object a cache handle, defaulting to a memory caching driver that behaves like a class data hash.

    -sam

      Referencing class data in an object method directly makes it hard to cleanly override the object method in a sub-class. How would you write an overridden wear_out_sole()?

      But it wasn't hard, and seems to work fine, as shown above in the original post (you might not've noticed that it was indeed overridden in the Boot class). Is there anything wrong with Boot::wear_out_sole in the OP?

      I think there's something I'm missing here. In your comment, are you implying that a subclass should be able to access class data (since a Boot *is*, after all, a Shoe)?

      All that aside, I think you'll find that it's pretty unusual to use class data in a real OO system.

      Yes, I think I'm noticing that. Thank you. The only example I ever see is when a class wants to keep a total of objects. And for something that simple, there are other ways of doing it (like just incrementing a global every time you instantiate an object, or counting rows in a db table, or keeping the objects in question in a list (then you know the length of the list)).

        In your comment, are you implying that a subclass should be able to access class data (since a Boot *is*, after all, a Shoe)?

        Maybe not class data, but definitely class behavior -- and tracking the number of shoes in the system is behavior.

Re: Still not getting it: hashref OO class variables
by ikegami (Patriarch) on Feb 14, 2008 at 22:38 UTC
    The I think the section of the docs in question is very unclear, but I think it's an argument for using accessors. For example, provide and use incr_num_holey instead of dealing with $num_holey directly (which you half-do).
Re: Still not getting it: hashref OO class variables
by NetWallah (Canon) on Feb 15, 2008 at 00:28 UTC
    You might be tempted to use CLASS data to store references, counts and global information for collections of objects.

    A better solution to that issue is to define a new collection class that holds these counters, and global information. As new objects are created, they should be added to an instance of the collection class - or better, use a method in the collection class to create instances of the sub-objects - that way you can manage them collectively.

    That said, here is updated code for your Shoe.pm that ignores the advice above, but allows you to implement the Boot class without any methods (disable the current methods).

    Update:
    And here is a modified Shoetest.pl that includes a new ShoeRack class that uses the collection method indicated above.

         "As you get older three things happen. The first is your memory goes, and I can't remember the other two... " - Sir Norman Wisdom