NAME

Class - Lightweight Perl object system with parent-first BUILD and method copying

VERSION

Version v0.1.1

SYNOPSIS

use Class;

# Simple class with attributes and BUILD
package Person;
use Class;

sub BUILD {
    my ($self, $attrs) = @_;
    $self->{full_name} = $attrs->{first} . ' ' . $attrs->{last};
}

package Employee;
use Class;
extends 'Person';

sub BUILD {
    my ($self, $attrs) = @_;
    $self->{employee_id} = $attrs->{id};
}

# Create an object
my $emp = Employee->new(first => 'John', last => 'Doe', id => 123);

print $emp->{full_name};   # John Doe
print $emp->{employee_id}; # 123

# Using roles if Role.pm is available
package Manager;
use Class;
with 'SomeRole';
my $mgr = Manager->new();

DESCRIPTION

Class provides a lightweight Perl object system with:

  • Parent-first constructor building via BUILD methods.

  • Simple inheritance via extends with method copying.

  • Optional role consumption via with and does (if Role module is available).

  • Automatic caching of BUILD order for efficient object creation.

  • Optimized method copying for better performance.

This module includes performance optimizations such as cached BUILD method resolution, efficient parent class loading, and optimized method copying with caching.

BUILD METHODS

Classes can define a BUILD method:

sub BUILD {
    my ($self, $attrs) = @_;
    # initialize object
}

All BUILD methods in the inheritance chain are called in parent-first order during new. The order is determined by depth-first traversal, ensuring that parent classes are always initialized before their children.

For diamond inheritance patterns:

  A
 / \
B   C
 \ /
  D

BUILD methods are called in the order: A, B, C, D (true parent-first order)

METHOD COPYING

This system copies public methods from parent classes to child classes. This design enables:

  • Direct method access in child symbol tables

  • Proper functioning of object cloning

  • Better performance for frequently called methods

  • Compatibility with code that expects direct method access

The following methods are NOT copied:

  • Special methods (BUILD, new, extends, with, does, import, AUTOLOAD, DESTROY)

  • Private methods (starting with underscore)

  • Package metadata (ISA, VERSION, EXPORT, etc.)

ROLES

If a Role module is available, you can consume roles via:

with 'RoleName';
does 'RoleName';

This provides role-based composition for shared behavior. The Role module must be installed separately.

PERFORMANCE OPTIMISATIONS

This version includes significant performance improvements:

  • Cached BUILD method resolution using depth-first parent-first order

  • Precomputed skip patterns for fast method filtering

  • Method copying cache to avoid duplicate operations

  • Efficient parent class loading with minimal overhead

  • Optimized symbol table scanning

CACHING

Class uses internal caches to optimise performance:

  • %BUILD_METHODS_CACHE - caches linearised parent-first build order

  • %METHOD_COPY_CACHE - tracks which parent-child pairs have had methods copied

Caches are automatically updated when inheritance changes via extends.

ERROR HANDLING

  • Recursive inheritance is detected and throws an exception.

  • Failure to load a parent class is non-fatal (parent might be defined inline).

EXAMPLES

Basic Inheritance with Method Copying

package Animal;
use Class;
sub speak { "animal sound" }
sub eat   { "eating" }

package Dog;
use Class;
extends 'Animal';
sub speak { "woof" }  # Overrides parent method

my $dog = Dog->new;
print $dog->speak;  # "woof" (from Dog)
print $dog->eat;    # "eating" (copied from Animal)

# Method is copied to Dog's symbol table
no strict 'refs';
print defined &Dog::eat ? "copied" : "not copied";  # "copied"

Diamond Inheritance

package A;
use Class;
sub BUILD { print "A BUILD\n" }

package B;
use Class;
extends 'A';
sub BUILD { print "B BUILD\n" }

package C;
use Class;
extends 'A';
sub BUILD { print "C BUILD\n" }

package D;
use Class;
extends 'B', 'C';
sub BUILD { print "D BUILD\n" }

my $d = D->new;
# Output: A BUILD, B BUILD, C BUILD, D BUILD

Object Cloning with Method Copying

package Base;
use Class;
sub clone_method { "works" }

package Child;
use Class;
extends 'Base';

my $original = Child->new;
my $cloned = bless { %$original }, ref($original);

# Works because methods are copied to Child
print $cloned->clone_method;  # "works"

METHODS

new

my $obj = Class->new(%attributes);

Constructs a new object of the class, calling all BUILD methods from parent classes in parent-first order. All attributes are passed to BUILD as a hashref.

The constructor uses cached BUILD method references for optimal performance, especially in deep inheritance hierarchies.

_compute_build_methods

my $build_methods = _compute_build_methods($class);

Internal method that computes the BUILD methods in parent-first order using depth-first traversal.

This ensures BUILD methods are called from the root parent down to the child class, which is essential for proper initialisation in inheritance hierarchies.

_depth_first_traverse

_depth_first_traverse($class, \@order, \%visited);

Internal recursive method that performs depth-first traversal of the inheritance hierarchy.

This method ensures that parent classes are always processed before their children, which is crucial for correct BUILD method ordering.

extends

extends 'ParentClass';
extends 'Parent1', 'Parent2';

Adds one or more parent classes to the calling class. This method:

  • Automatically loads parent classes if not already loaded

  • Prevents recursive inheritance

  • Copies public methods from parents to children

  • Maintains inheritance via @ISA

  • Clears relevant caches to ensure consistency

Method copying is performed to ensure that inherited methods are directly available in the child class's symbol table, which enables features like object cloning to work correctly.

_copy_public_methods

_copy_public_methods($child_class, $parent_class);

Internal method that copies public methods from parent to child class. This method:

  • Skips special methods (BUILD, new, extends, etc.)

  • Skips private methods (starting with underscore)

  • Uses caching to avoid duplicate copying

  • Only copies methods not already defined in child

This optimised implementation uses precomputed skip patterns and caching for better performance.

_delete_build_cache

_delete_build_cache($class);

Internal method that clears the BUILD methods cache for a class and all classes that inherit from it.

This ensures cache consistency when inheritance relationships change. Also clears method copy caches for affected classes.

_inherits_from

_inherits_from($class, $parent);

Internal recursive method that checks if a class inherits from another class, either directly or indirectly.

Returns true if $class inherits from $parent, false otherwise.

IMPORT

use Class;
use Class 'extends' => 'Parent';

When imported, Class automatically installs the following functions into the caller's namespace:

  • new - constructor

  • extends - inheritance helper

  • with and does - if Role.pm is available

Optionally, you can specify extends in the import statement to immediately set a parent class:

use Class 'extends' => 'Parent';

The import method also enables strict and warnings in the calling package.

AUTHOR

Mohammad Sajid Anwar, <mohammad.anwar at yahoo.com>

REPOSITORY

https://github.com/manwar/Class-Mite

BUGS

Please report any bugs or feature requests through the web interface at https://github.com/manwar/Class-Mite/issues. I will be notified and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

perldoc Class

You can also look for information at:

LICENSE AND COPYRIGHT

Copyright (C) 2025 Mohammad Sajid Anwar.

This program is free software; you can redistribute it and / or modify it under the terms of the the Artistic License (2.0). You may obtain a copy of the full license at:

http://www.perlfoundation.org/artistic_license_2_0

Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license.

If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license.

This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder.

This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed.

Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.