-
Notifications
You must be signed in to change notification settings - Fork 19
Class Data and Methods
Please see the main page of the repo for the actual RFC. As it states there:
Anything in the Wiki should be considered "rough drafts."
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 common to indicate class methods or variables are shared across the class and all instances of this class.
common $foo; # class data
common method foo () {...} # class methodIn 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;
common $counter = 0;
common method create($type) {
my $target = $class->get_factory_type($type);
$counter++;
return $target->new;
}
common 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 common data and methods are attached to classes, not roles. Thus, if we have this:
role DoesSomething {
common $count = 0;
common 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;
common $class_data;
common 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 common 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