NAME

OO::Closures - Object Oriented Programming using Closures.

SYNOPSIS

use OO::Closures;

sub new {
    my (%methods, %ISA, $self);
    $self = create_object (\%methods, \%ISA, !@_);

    ...

    $self;
}

DESCRIPTION

This package gives you a way to use Object Oriented programming using Closures, including multiple inheritance, SUPER:: and AUTOLOADing.

To create the object, call the function create_object with three arguments, a reference to a hash containing the methods of the object, a reference to a hash containing the inherited objects, and a flag determining whether the just created object is the base object or not. This latter flag is important when it comes to trying AUTOLOAD after not finding a method.

create_object returns a closure which will act as the new object.

Here is an example of the usage:

use OO::Closures;
sub dice {
    my (%methods, %ISA, $self);
    $self = create_object (\%methods, \%ISA, !@_);

    my $faces = 6;

    $methods {set}  = sub {$faces = shift;};
    $methods {roll} = sub {1 + int rand $faces};

    $self;
}

It is a simple object representing a die, with 2 methods, set, to set the number of faces, and roll, to roll the die. It does not inherit anything. To make a roll on a 10 sided die, use:

(my $die = dice) -> (set => 10);
print $die -> ('roll');

Note that since the objects are closures, method names are the first arguments of the calls.

OBJECT VARIABLES

One can make object variables available to the outside world as well. Just like in Eiffel, for an outsider this will be indistinguishable from accessing a argumentless method. (However, in a Perlish fashion, we will actually allow arguments in the call). To do so, instead of putting a code reference in the %methods hash, put a reference to a scalar in the hash. Note that to the outside world, no more than read only access to the variable is given.

Here is an example:

sub dice {
    my (%methods, %ISA, $self);
    $self = create_object (\%methods, \%ISA, !@_);

    my $faces = 6;

    $methods {set}   = sub {$faces = shift;};
    $methods {roll}  = sub {1 + int rand $faces};

    $methods {faces} = \$faces;

    $self;
}

(my $die = dice) -> (set => 10);
print $die -> ('faces');

This will print 10.

INHERITANCE

To use inheritance, we need to set the %ISA hash. We also need to pass ourselves to the classes we inherited, so an inherited class can find the base object. (This is similar to the first argument of the constructor when using regular objects).

Here is an example that implements multi dice, by subclassing dice. We will also give dice a method print_faces that prints the number of faces and returns the object.

use OO::Closures;

sub dice {
    my (%methods, %ISA, $self);
    $self = create_object (\%methods, \%ISA, !@_);
    my $this_object = shift || $self;

    my $faces = 6;

    $methods {set}         = sub {$faces = shift};
    $methods {roll}        = sub {1 + int rand $faces};
    $methods {print_faces} = sub {print "Faces: $faces\n"; $this_object};

    $self;
}

sub multi_dice {
    my (%methods, %ISA, $self);
    $self = create_object (\%methods, \%ISA, !@_);
    my $this_object = shift || $self;

    %ISA  = (dice => dice $this_object);

    my $amount = 1;

    $methods {amount} = sub {$amount = shift};
    $methods {roll}   = sub {
        my $sum = 0;
        foreach (1 .. $amount) {$sum += $self -> ('dice::roll')}
        $sum;
    };

    $self;
}

my $die = multi_dice;
$die -> (set    => 7);
$die -> (amount => 4);
print $die -> ('print_faces') -> ('roll'), "\n";
__END__

Notice the line my $this_object = shift || $self;. That will make $this_object contain the base object, unlike $self which is the instance of the current class.

The class dice is subclassed in multi_dice by calling dice with an extra argument, the base object. Now it's known that dice is subclassed, and looking for AUTOLOAD if it cannot find the requested method should not happen; that will be triggered by the base object.

Inherited classes are named, but they are named by the inheriter, not the inheritee. This allows you to inherit the same class multiple times, and getting separate data and method space for it.

When searching for methods in the inheritance tree, no order will be garanteed. If you subclass multiple classes defining the methods with the same name, it's better to mask those methods and explicitely redirect the call to the class you want it to handle.

You can call a method by prepending its class name(s); just like regular objects.

Inherited classes are stored in the %ISA hash, but since this variable is private to the object, each object can have its own inheritance structure. If you change a class, existing objects of the class will not be modified.

The pseudo class 'SUPER::' works the same way as regular objects do, except that it works the right way. It will resolve 'SUPER::' depending on the inherited classes of the object the method is called in; not on the @ISA of the package the call is made from.

use OO::Closures;

By default, the module OO::Closures exports the function create_object. If you want this function to be known by another name, give that name as an argument to the use statement.

use OO::Closure 'other_name';

Now you create objects with other_name (\%methods, \%ISA, !@_);

BUGS

This documentation uses the word 'class' in cases where it's not really a class in the sense of the usual object oriented way. Mark-Jason Dominus calls this class-less object orientism.

HISTORY

$Log: Closures.pm,v $
Revision 1.2  1999/08/02 06:06:04  abigail
Bug fixes and more efficient use of code (Rick Delaney).
Free and open software copyright/license.
Scalar references as methods (to complement for Eiffel like features).
CPAN friendly module.

Revision 1.1  1998/10/01 22:54:57  abigail
Initial revision

AUTHOR

This package was written by Abigail, abigail@delanet.com.

COPYRIGHT and LICENSE

This code is copyright 1998, 1999 by Abigail.

This code is free and open software. You may use, copy, modify, distribute, and sell this program (and any modified variants) in any way you wish, provided you do not restrict others from doing the same.