NAME
Perl6::Classes - First class classes in Perl 5
SYNOPSIS
use Perl6::Classes;
class Composer {
submethod BUILD { print "Giving birth to a new composer\n" }
method compose { print "Writing some music...\n" }
}
class ClassicalComposer is Composer {
method compose { print "Writing some muzak...\n" }
}
class ModernComposer is Composer {
submethod BUILD($) { $.length = shift }
method compose() { print((map { int rand 10 } 1..$.length), "\n") }
has $.length;
}
my $beethoven = new ClassicalComposer;
my $barber = new ModernComposer 4;
my $mahler = ModernComposer->new(400);
$beethoven->compose; # Writing some muzak...
$barber->compose # 7214
compose $mahler; # 89275869347968374698756....
DESCRIPTION
Perl6::Classes
allows the creation of (somewhat) Perl 6-style classes in Perl 5. The following features are currently supported:
sub
s,method
s, andsubmethod
sAnd their respective scoping rules.
Attributes
Which are available through the
has
keyword, and look like$.this
.Inheritance
Both single and multiple inheritance are available through the
is
keyword.Signatures
Signatures on
method
s,sub
s, andsubmethod
s are supported, but just the Perl 5 kind.Data hiding
Using the
public
,protected
, andprivate
traits, you can enforce (run-time) data hiding. This is not supported on attributes, which are alwaysprivate
.Anonymous classes
That respect closures. You can now nest them inside methods of other classes, even other anonymous ones!
The Perl6::Classes
module augments Perl's syntax with a new declarator: class
. It offers the advantage over Perl's standard OO mechanism that it is conceptually easier to see (especially for those from a C++/Java background). It offers the disadvantage, of course, of being less versatile.
Declarations
Inside a class
, the following things can be declared:
method
-
A method is a routine on an object of the class that can be inherited by derived classes. Declare it just like a
sub
, with the wordmethod
in place ofsub
. Both$_
and$self
are set to the invocant, and the arguments (without the invocant) are passed in@_
. By default,method
s are public. sub
-
A good ol' familiar sub is a method that takes the class itself as an invocant. It may not use attributes, but you can call it from an object and it acts polymorphically. In any case,
$_
and$self
are set to the class name for a named class, and the class object for one of the anonymous variety. By default,sub
s are public. submethod
-
A submethod is just like a
method
, except that it does not participate in inheritance. Most often, routines that create, initialize, or destroy the current object fall into this category (Wall). They are declared and behave just likemethod
s, otherwise. Except they default to private. has
-
has
declares an attribute, which is some private instance data. They generally look like$.this
, but can look like@.that
or%.uhm
, too. They behave like scalars, arrays, and hashes (respectively), too, except that there's just a dot in front of their name. So, you can dereference%.uhm
with$.uhm{right}
. They are always private, and can't be declared otherwise.
Inheritance
You may inherit as many classes as you like by following the name of the declared class (or the absence of one, in the case of anonymous classes) with repeated "is ClassName"s. For instance:
class Pegasus is Human is Horse { ... }
A derived class (Pegasus
in this case) inherits all sub
s and method
s (but not submethod
s) of its base classes (Human
and Horse
). All of these behave "more polymorphically" than regular Perl 5 inheritance with use base
and @ISA
. For instance:
class Base { method go { ... } }
class Derived is Base { method go { ... } }
my $b = new Base;
my $d = new Derived;
$b->go; # Base::go
$d->go; # Derived::go
my $method = \&Base::go;
$b->$method; # Base::go
$d->$method # Derived::go
Whether this is a bug or a feature is left to the opinion of the reader.
No, you can't derive from an anonymous class. No, not even if it's in a variable. Don't mistake that for not being able to derive anonymous classes from named ones, though. You're allowed to do that.
Constructors and Destructors
There are two layers of constructors and destructors. There's the Perl constructor, often called new
, which actually constructs the object. Then there's the initializer, which C++ and Java call the constructor, under the name BUILD
. Perl6::Classes
takes care of the constructor for you, and allows you to specify the initializer, usually as a submethod
.
The naming is a bit less intuitive as far as destructors. Perl herself doesn't let you specify a real destructor, just a de-initialzer which is called just before the memory is reclaimed. This is under the name DESTROY
. But Perl6::Classes
handles that for you and allows you to specify DESTRUCT
, which essentially does the same thing, except when you're inheriting.
Perl6::Classes
doesn't pay attention to (de-)initializer return values, so if an error occurs, you should throw an exception. Perl will ignore the exception if it's in the destructor.
Constructors and Destructors and Inheritance
When you're inheriting base classes, each base class's constructor is called before the derived one, in the order specified on the declaration line. This happens even if the derived class explicitly specifies an initializer. Similarly, each base class's destructor is called after the derived one, in the reverse order.
Data Hiding
Perl6::Classes
offers standard run-time data protection, for whatever it's worth. It is specified on methods (and subs and submethods) by using traits. Particularly, is public
, is protected
, and is private
. Traits are specified right after the signature (or the absence thereof) of a declaration. For instance:
class Thingy {
method describe { print $_->description, "\n"; }
method baseclass is protected { "Thingy" }
method description is private { "This " . $->baseclass . " is neat" }
}
This class allows you to override anything, but is probably hoping you'll override description
. However, clients of Thingy
can only access describe
. Classes derived from Thingy
may access describe
and baseclass
, and only the describe
method (and other potential Thingy
methods) can access description
.
Data Hiding and Constructors
It is sometimes useful to make a private or protected constructor, saying that "only my children or I are allowed to make me". But, making BUILD
private doesn't work, becuase BUILD
is called through the implicit sub new
. What you really need to do is make new
private. This is how:
class Handle {
sub new is private { ... }
sub makeHandle { new Handle }
}
Now, new Handle
from outside the class will cause an error, but makeHandle
works fine. You may put yada-yada-yada (...) inside that as in the example, as the codeblock specified is never compiled. The declaration there is just to specify scope.
Note that a class with a private constructor may not effectively be derived from, as it will croak when the derived class tries to construct it. However, it is possible to specify an abstract class by making the constructor protected
.
Traps for the unwary
As just mentioned, new
's body is never compiled. You could catch yourself off guard by specifying a body, and seeing it never run. Future versions may check that the body of new is either unspecified or exactly "...".
Do not attempt to explicitly bless into a Perl6::Classes
class. Always use the new
function. Sure, a real package is created, but the subs in it don't behave how you'd think they would.
BUGS
There are undoubtedly bugs that I don't mention here. I mean, it's a source filter.
Code like this:
class Foo is Bar { method go { $_->Bar::go } }
Doesn't work the way you want it to. Instead, it calls Foo::go.
At the moment, line numbers in your source get all messed up by using a
class
.
SEE ALSO
perlobj, Class::Struct, Class::*
AUTHOR
Both the Perl6::Classes
module and this documentation were written by Luke Palmer (fibonaci@babylonia.flatirons.org
).
This module is licenced under the same terms as Perl itself. Copyright (C) 2003, Luke Palmer.