| Perl6-Classes documentation | view source | Contained in the Perl6-Classes distribution. |
Perl6::Classes - First class classes in Perl 5
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....
Perl6::Classes allows the creation of (somewhat) Perl 6-style classes
in Perl 5. The following features are currently supported:
subs, methods, and submethodsAnd their respective scoping rules.
Which are available through the has keyword, and look like $.this.
Both single and multiple inheritance are available through the is keyword.
Signatures on methods, subs, and submethods are supported, but
just the Perl 5 kind.
Using the public, protected, and private traits, you can enforce
(run-time) data hiding. This is not supported on attributes, which are
always private.
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.
Inside a class, the following things can be declared:
methodA 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 word method
in place of sub. Both $_ and $self are set to the invocant,
and the arguments (without the invocant) are passed in @_. By default,
methods are public.
subA 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, subs are public.
submethodA 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 like methods, otherwise. Except they default to private.
hashas 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.
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 subs and methods
(but not submethods) 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.
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.
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.
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.
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.
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.
There are undoubtedly bugs that I don't mention here. I mean, it's a source filter.
class Foo is Bar {
method go { $_->Bar::go }
}
class.perlobj, Class::Struct, Class::*
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.
| Perl6-Classes documentation | view source | Contained in the Perl6-Classes distribution. |