NAME

Package::Data::Inheritable - Inheritable and overridable package data/variables

VERSION

Version 0.03

SYNOPSIS

Method interface:

package BaseClass;
use base qw( Package::Data::Inheritable );

BEGIN {
    BaseClass->pkg_inheritable('$class_scalar' => 'a not so ordinary package variable');
};

print $class_scalar;

Exporter like interface:

package Derived;
use base qw( BaseClass );

BEGIN {
    # declare our variables and overrides *before* inheriting
    our @EXPORT_INHERIT = qw( $scalar @array );

    inherit BaseClass;
}
our @array = (1,2,3);
our $scalar;

print $class_scalar,
      @array, $scalar;

DESCRIPTION

This module tries to deliver inheritable package data (variables) with a reasonably convenient interface. After declaration the variables can be used like ordinary package variables. Most importantly, these variables can be inherited by derived classes (packages) by calling the inherit() method. If a derived class doesn't call inherit() it will still get the ordinary method inheritance and will also be able to define its vars and make them inheritable by its subclasses.

Within your class (hierarchy) code you will benefit from compiler checks on those variables. The overall result is close to real class data as opposed to class methods. Of course you can wrap your variables in accessor/mutators methods as you need.

The semantic provided mimics the static data members in languages like C++ and Java. When you assign to an inherited variable within a derived class, every class in the inheritance hierarchy will see the new value. If you want to override a variable you must redeclare it explicitly.

Two interfaces are provided, one is based on the method pkg_inheritable() and the other one is Exporter like. The variable visibility (scope) depends on the interface you used. If you use the Exporter like interface, variables will be declared via our, while if you use the method interface it will be like you had imported those variables.

EXPORT

Package::Data::Inheritable is an Exporter, inheriting from it (via use base or @ISA) will make your class an Exporter as well. The package variable @EXPORT_INHERIT contains the symbols that will be inherited and @EXPORT_OK will always contain at least those symbols.

The Exporter like interface allows your class to set @EXPORT_INHERIT in pretty much the same way you would set @EXPORT and @EXPORT_OK with Exporter.

DEFINING VARIABLES

Method interface

BEGIN {
    Class->pkg_inheritable('$scalar');
    Class->pkg_inheritable('@array' => [1,2,3]);
}

Every variable declaration must be inside a BEGIN block because there's no 'our' declaration of that variable and we need compile time installation of that symbol in the package symbol table.

Exporter like interface

BEGIN {
    our @EXPORT_INHERIT = qw( $scalar @array );
}
our $scalar;
our @array = (1,2,3);

If you're defining variables, none of which is overriding a parent package's one (see overriding below), it's not required to define @EXPORT_INHERIT inside a BEGIN block. You will declare the variables via 'our' in the usual way. The actual our declaration of each variable must be outside the BEGIN block in any case because of 'our' scoping rules.

OVERRIDING VARIABLES

When you use the Exporter like interface and you want to override a parent package variable you must define @EXPORT_INHERIT before calling inherit(), otherwise inherit() will not find any of your overrides. On the contrary, if you use the pkg_inheritable() method interface, ordering doesn't matter.

METHODS

inherit

Make the caller package inherit variables from the package on which the method is invoked. i.e.

package Derived;
  BEGIN {
    inherit Base;
    # or
    Base->inherit;
  }

will make Derived inherit variables from Base.

This method must be invoked from within a BEGIN block in order to install the inherited variables at compile time. Otherwise any attempt to refer to those package variables in your code will trigger a 'Global symbol "$yourvar" requires explicit package name' error.

pkg_inheritable

Class->pkg_inheritable('$variable_name');
Class->pkg_inheritable('$variable_name' => $value);
Class->pkg_inheritable('@variable_name' => ['value1','value2']);

This method implements the non-exporter like interface. $variable_name will be installed in the package symbol table like it had been declared with use 'vars'. Furthermore the variable will be inherited by packages invoking inherit() on class 'Class'.

EXAMPLES

Inheriting and overriding

use Package::Data::Inheritable;

# set up Base class with the method interface:
 package Base;
 use base qw( Package::Data::Inheritable );

 BEGIN {
     Base->pkg_inheritable('$scalar1' => 'Base scalar');
     Base->pkg_inheritable('$scalar2' => 'Base scalar');
     Base->pkg_inheritable('@array'   => [1,2,3]);
 };

 print $scalar1;
 print @array;

# set up Derived class with the Exporter like interface:
 package Derived;
 use base qw( Base );

 BEGIN {
     # declare our variables and overrides *before* inheriting
     our @EXPORT_INHERIT = qw( $scalar2 @array );

     inherit Base;
 }
 our @array = (2,4,6);
 our $scalar2 = "Derived scalar";

 # prints "Derived scalar"
 print $scalar2;
 # prints "Base scalar"
 print $Base::scalar2;
 # prints 246
 print @array;
 # prints "Base scalar"
 print $scalar1;
 $scalar1 = "Base and Derived scalar";
 # prints "Base and Derived scalar" twice
 print $Base::scalar1, $Derived::scalar1;

Accessing and wrapping data members

Be aware that when you qualify your variables with the package prefix you're giving up compiler checks on those variables. Furthermore, access to class data from outside your classes is better avoided.

  use strict;
  package Base;
  use base qw( Package::Data::Inheritable );

  BEGIN {
      Base->pkg_inheritable('$_some_scalar' => 'some scalar');
      Base->pkg_inheritable('$public_scalar' => 'public scalar');
  };

  sub new { bless {}, 'Base' }

  # accessor/mutator example
  sub some_scalar {
      my $class = shift;
      if (@_) {
         my $val = shift;
         # check $val or croak...
         $_some_scalar = $val;
      }
      return $_some_scalar;
  }

  sub do_something {
      my ($self) = @_;
      # ok
      print $public_scalar;
      # ok, but dangerous
      print $Base::public_scalar;

      # compile error
      print $publicscalar;

      # variable undefined but no compile error because of package prefix
      print $Base::publicscalar;
  }


  package Derived;
  use base qw( Base );
  BEGIN {
      inherit Base;
  };
  


And then in some user code:

  use strict;
  use Base;
  use Derived;
  
  # prints "public scalar". Discouraged.
  print $Base::public_scalar;
  # prints "some scalar"
  print Base->some_scalar;
  
  Base->some_scalar("reset!");
  my $obj = Base->new;
  # prints "reset!"
  print Base->some_scalar;
  print $obj->some_scalar;

  # prints "reset!"
  print Derived->some_scalar;
  Derived->some_scalar("derived reset!");
  # prints "derived reset!"
  print Derived->some_scalar;
  # prints "derived reset!"
  print Base->some_scalar;

CAVEATS

The interface of this module is not stable yet. I'm still looking for ways to reduce the amount of boilerplate code needed. Suggestions and comments are warmly welcome.

AUTHOR

Giacomo Cerrai, <gcerrai at cpan.org>

BUGS

Please report any bugs or feature requests to bug-package-data-inheritable at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Package-Data-Inheritable. 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 Package::Data::Inheritable

You can also look for information at:

SEE ALSO

Class::Data::Inheritable,

ACKNOWLEDGEMENTS

COPYRIGHT & LICENSE

Copyright 2007 Giacomo Cerrai, all rights reserved.

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