-
Notifications
You must be signed in to change notification settings - Fork 19
Class Data and Methods
Click here to provide feedback.
In OO programming, you have the class and instances of that class. Most of the time we operate at the instance level, but there are times we need to operate at the class level before you have an instance.
We propose the modifier/keyword shared
to indicate class methods or variables are shared across the class and all instances of this class.
shared $foo; # class data
shared method foo () {...} # class method
In Perl, the most common class method is new
. However, there are other times we might need a class method, such as for a factory class, or for helper methods for building objects, but prior to the instantiation. For example, for a factory, we might have something like this:
class SomeFactory {
has $some_var;
shared $counter = 0;
shared method create($type) {
my $target = $class->get_factory_type($type);
$counter++;
return $target->new;
}
shared method get_factory_type($type) { ... }
}
In the above, instead of a $self
variable being injected, we have a $class
variable. It is not an instance. Instead, it's just an alias for the invoking package name. We cannot simply use __PACKAGE__
because if we subclass our factory, __PACKAGE__
in SomeFactory
would be the parent package, not the child package.
In the create
and get_factory_type
methods, we have access to the $counter
class data, but not to the $some_var
instance data. that's because $some_var
doesn't exist until an instance is created and class methods are called before that.
Note that shared
data and methods are attached to classes, not roles. Thus, if we have this:
role DoesSomething {
shared $count = 0;
shared method foo () {...}
}
class First does DoesSomething {...}
class Second does DoesSomething {...}
The First
and Second
classes each have separate $count
and foo
methods. Thus, if you increment the $count
value in the First
class, the Second
class's $count
value will be unchanged.
class Foo {
has $instance_data;
shared $class_data;
shared method foo () {
...
}
method bar () {
...
}
}
It should go without saying, but I've seen this trip up newer programmers in other languages enough that I'll say it anyway: instance variables and methods cannot be accessed by class methods. Thus, in the foo
method, if we call $class->bar
, we get an exception because that is an instance method and presumably its precise behavior (though not semantics, hopefully) can vary from instance to instance.
By the same token, foo
cannot not access $instance_data
because it can't know which value to pull from which instance.
However, instance methods can always call class methods or access class data because they are "global" for the class.
Generally speaking, a method is an instance or class method. An overriding method in a subclass should not be able to change this status.
For some this shared
behavior might seem like an over complication. Why not just do this?
sub create ($class, $type) {
my $target = $class->get_factory_type($type);
$counter++;
return $target->new;
}
Sure, it's a touch more typing, but no new syntax!
The problem is that Corinna needs to understand if something is a method or a subroutine. If I call $some_class->foo
, I want to know that I called a method and not some helper function that's been imported into this $some_class
. By the same token, roles want to know that they're flattening methods into your class and not subroutines.
The lack of distinction between subroutines and methods has caused all sorts of curious workarounds to appear in Perl code. namespace::autoclean
is a perfect example. Or just read through the code of various modules trying to implement roles to see the heuristics they go through to figure out what can and cannot be flattened into a consuming class.
As an aside, we can think of instance methods as being prefixed by has
the same way instance variables are:
has $x;
has method foo () { ... }
However, we omit the has
because this is the common case. Whether or not Corinna will support has method ...
syntax is unknown at this time.
Corinna—Bringing Modern OO to Perl