package AbstractClass; $VERSION = 0.12; use Carp; sub bless ($@) { my $class = $_[1] || caller(); if (exists $Registered{$class}) { confess("Cannot bless objects into abstract class $class"); } else { CORE::bless(shift, $class); } } $text = ' #line 1 "(AbstractClass loaded for MYPACK)" package MYPACK; sub import { my $pkg = shift; return if $pkg eq "MYPACK"; foreach my $meth (@ABSTRACT_METHODS) { my $does = $pkg->can($meth); if (not defined($does)) { Carp::croak("Class $pkg must define $meth for class MYPACK"); } else { my $override = MYPACK->can($meth); if (defined ($override) and $does == $override) { Carp::confess("Class $pkg cannot inherit $meth from MYPACK"); } } } $pkg->SUPER::import(@_); } 1; '; sub import { shift; # Don't need my class name my $base = caller(); $Registered{$base}++; *{"$base\::bless"} = *bless; @{"$base\::ABSTRACT_METHODS"} = @_; my $eval_str = $text; $eval_str =~ s/MYPACK/$base/g; eval($eval_str) or confess("Cannot execute:\n$eval_str\n\nError $@"); } 1; __END__ =head1 NAME AbstractClass - Makes classes into abstract classes. =head1 SYNOPSIS In module SomeAbstractClass.pm: package SomeAbstractClass; use AbstractClass; @ABSTRACT_METHODS = qw(foo bar); or more compactly: package SomeAbstractClass; use AbstractClass qw(foo bar); =head1 DESCRIPTION An abstract class is a class which defines methods that must be overridden in classes that wish to inherit from it which are not themselves abstract classes. Normally the abstract class will then provide methods whose implementations need these methods to exist. Whether or not it is an abstract class, it would crash at some point if the methods were missing. By moving the check to when you first load the class, you can find problems immediately and get better reporting of the requirement. It is customary to not have any objects in an abstract class. This module provides some enforcement of this rule by overriding bless in abstract classes. =head1 BUGS Abstract classes are implemented with special import functions. Therefore this does not play well with Exporter. Also due to unfortunate restrictions in the implementation of Perl's SUPER pseudo-package, multiple inheritance will not play well with abstract classes. If you wish to use the capabilities of abstract classes and multiple inheritance, you may wish to look at the more intrusive Class::Contract. This mechanism also means that if you define multiple classes in a single file then you must manually import each derived class to test it. When each class is in its own module, this happens automatically when you use the module. It is not hard to get around the rule that objects cannot belong to an abstract class. To fix that would require overriding the core bless method, which brings up issues of its own. =head1 AUTHOR AbstractBase was written by Ben Tilly . This module may be copied and modified on the same terms as Perl itself.