NAME

UNIVERSAL::Object - A useful base class

VERSION

version 0.17

SYNOPSIS

package Person;
use strict;
use warnings;
use UNIVERSAL::Object;

our @ISA = ('UNIVERSAL::Object');
our %HAS = (
    name   => sub { die 'name is required' }, # required in constructor
    age    => sub { 0 },                      # w/ default value
    gender => sub {},                         # no default value
);

sub name   { $_[0]->{name}   }
sub age    { $_[0]->{age}    }
sub gender { $_[0]->{gender} }

package Employee;
use strict;
use warnings;

our @ISA = ('Person');
our %HAS = (
    %Person::HAS, # inheritance :)
    job_title => sub { die 'job_title is required' },
    manager   => sub {},
);

sub job_title { $_[0]->{job_title} }
sub manager   { $_[0]->{manager}   }

# ...

my $ceo = Employee->new(
    name      => 'Alice',
    job_title => 'CEO',
);

my $manager = Employee->new(
    name      => 'Bob',
    job_title => 'Middle Manager',
    manager   => $ceo,
);

my $pawn = Employee->new(
    name      => 'Joe',
    job_title => 'Line Worker',
    manager   => $manager,
);

DESCRIPTION

This is a simple base class that provides a protocol for object construction and destruction. It aims to be as simple as possible while still being complete.

SLOT MANAGEMENT

One of the key contributions of this module is to provide a mechanism for declaring the slots that a given class is expected to have. These are used in the object construction process to ensure that all slots are created and initialized.

%HAS

This is a public (our) package variable that contains an entry for each slot expected in the instance. The key is the slot's name, while the value is a CODE reference which, when called, will produce a default value for the slot.

NOTE: No inheritance of slot definitions is done between classes, this is left as an exercise to the author, however it is easily accomplished with the pattern shown above in the SYNOPSIS.

SLOTS ($class)

This is an accessor method for the %HAS variable in the $class package.

NOTE: If you choose to store the slot definitions elsewhere (not in %HAS) or store them in a different form (not key => CODE hash entries), it is possible to then override this method to return the expected values in the expected form.

INSTANCE REPRESENTATION

REPR

This returns a new HASH reference to use as the instance.

NOTE: If you wish to use a different instance type of some kind then you will need to override this method.

NOTE: The HASH that gets returned from here will eventually be blessed, which means you are limited to tie or XS MAGIC based solutions if you want this HASH reference to behave differently.

CONSTRUCTION PROTOCOL

Once we know the expected slots it is very easy to create a default constructor. This is the second key contribution of this module, to provide a consistent and complete protocol for the construction and destruction of instances.

NOTE: The method documentation is meant to be read from top to bottom, in that they are documented in the same order they are called.

new ($class, @args)

This is the entry point for object construction, from here the @args are passed into BUILDARGS. The return value of new should always be a fully constructed and initialized instance.

BUILDARGS ($class, @args)

This method takes the original @args to the new constructor and is expected to turn them into a canonical form, which is a HASH ref of name/value pairs. This form is considered a prototype candidate for the instance, and what BLESS and subsequently CREATE expect to receive.

NOTE: The values in the prototype candidate should be shallow copies of what was originally contained in @args, but this is not actually enforced, just suggested to provide better ownership distinctions.

BLESS ($class, $proto)

This method receives the $proto candidate from BUILDARGS and from it, ultimately constructs a blessed instance of the class.

This method really has two responsibilities, first is to call CREATE, passing it the $proto instance. Then it will take the return value of CREATE and bless it into the $class.

NOTE: This method will, if the REPR type is a HASH reference, proceed to lock the set of allowed keys in the HASH. Things should "Just Work" as long as you do not attempt to access a slot that you have not defined.

NOTE: Aside from the above, this method is mostly here to make it easier to override the CREATE method, which, along with the REPR method, can be used to change the behavior and/or type of the instance structure. By keeping the bless work here we make the work done in CREATE simpler with less mechanics.

CREATE ($class, $proto)

This method receives the $proto candidate from BLESS and return from it an unblessed instance structure that BLESS will then bless into the $class.

First it must call SLOTS (described above), followed by REPR (also described above) to get both the slot definitions and a newly minted HASH ref instance. Using these two things, along with the $proto candidate, we construct a complete blessed instance. This is accomplished by looping through the list of slots, using values in the $proto when available, otherwise using the slot initializers. The final unblessed HASH ref based instance is then returned.

NOTE: If you wish to use a different instance type of some kind then you will need to override this method.

BUILD ($self, $proto)

The newly blessed instance supplied by BLESS must still be initialized. We do this by calling all the available BUILD methods in the inheritance hierarchy in the correct (reverse mro) order.

BUILD is an optional initialization method which receives the blessed instance as well as the prototype candidate. There are no restrictions as to what this method can do other then just common sense.

NOTE: It is worth noting that because we call all the BUILD methods found in the object hierarchy, the return values of these methods are completely ignored.

DESTRUCTION PROTOCOL

The last thing this module provides is an ordered destruction protocol for instances.

DEMOLISH ($self)

This is an optional destruction method, similar to BUILD, all available DEMOLISH methods are called in the correct (mro) order by DESTROY.

DESTROY ($self)

The sole function of this method is to kick off the call to all the DEMOLISH methods during destruction.

SEE ALSO

UNIVERSAL::Object::Immutable

AUTHOR

Stevan Little <stevan@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 by Stevan Little.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.