Reputation: 315
I have class attribute, e. g., counter of created objects in some base class,
package A;
our $counter = Counter->new; # not just a counter in fact, so initialization code should be inherited by descendants as well
sub new {
$counter++;
bless {}
}
sub get_counter {
$counter
}
package B;
use base 'A';
package main;
B->get_counter();
I want package B to have his own copy of this class attribute (e. g., counting objects of B class only), and all inherited methods from package A should deal with this copy. What is the correct way to implement this in plain perl and in Moo/Moose? Seems like MooX::ClassAttribute can not be inherited. One ugly solution found is to repeat attribute initialization code in each descendant and use symbolic dereference like ${"${class}::counter"} in ancestor's methods to access this attribute with actual package name. But seems like there should be more elegant way.
Upvotes: 1
Views: 293
Reputation: 57600
The default Perl object model has no concept of class attributes. And there's no kind of hook like “when a new subclass is created, run this code”.
Instead, the base class could maintain a hash of counters, using the class name as keys:
package A;
my %counters;
sub new {
my ($class) = @_;
my $counter = $counters{$class} //= Counter->new;
$counter++;
return bless {} => $class;
}
sub get_counter {
my ($self_or_class) = @_;
my $class = (ref $self_or_class) || $self_or_class;
$counters{$class};
}
package B;
use parent -norequire, 'A';
This will create a new counter when an instance of a subclass is created. Note that the first argument to a method is either the class name or the object instance. We need to use that in new()
as the hash key. In get_counter()
I've written this in a way that the method can be called on both a class and an object to the same effect.
A similar technique is known as inside-out objects, where store object fields in a hash held by the class, so that the object itself doesn't contain any data.
(Why parent
instead of base
? The parent
module only does inheritance, whereas base
also integrates with the fields
pragma which you should not use.)
Upvotes: 3