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:

  • subs, methods, and submethods

    And 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 methods, subs, and submethods are supported, but just the Perl 5 kind.

  • Data hiding

    Using the public, protected, and private traits, you can enforce (run-time) data hiding. This is not supported on attributes, which are always private.

  • 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 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.

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, subs 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 like methods, 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 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.

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.