NAME

Hash::AutoHash - Object-oriented access to real and tied hashes

VERSION

Version 1.15

SYNOPSIS

use Hash::AutoHash;

# real hash
my $autohash=new Hash::AutoHash name=>'Joe', hobbies=>['hiking','cooking'];

# access or change hash elements via methods
my $name=$autohash->name;           # 'Joe'
my $hobbies=$autohash->hobbies;     # ['hiking','cooking']
$autohash->hobbies(['go','chess']); # hobbies now ['go','chess']

# you can also use standard hash notation and functions
my($name,$hobbies)=@$autohash{qw(name hobbies)};
$autohash->{name}='Moe';            # name now 'Moe'
my @values=values %$autohash;       # ('Moe',['go','chess'])

# tied hash. 
use Hash::AutoHash qw(autohash_tie);
use Tie::Hash::MultiValue;          # from CPAN. each hash element is ARRAY
my $autohash=autohash_tie Tie::Hash::MultiValue;
$autohash->name('Joe');
$autohash->hobbies('hiking','cooking');
my $name=$autohash->name;           # ['Joe']
my $hobbies=$autohash->hobbies;     # ['hiking','cooking']

# real hash via constructor function. analogous to autohash_tied
use Hash::AutoHash qw(autohash_hash);
my $autohash=autohash_hash name=>'Joe',hobbies=>['hiking','cooking'];
my $name=$autohash->name;           # 'Joe'
my $hobbies=$autohash->hobbies;     # ['hiking','cooking']

# autohash_set is easy way to set multiple elements at once
# it has two forms
autohash_set($autohash,name=>'Moe',hobbies=>['go','chess']);
autohash_set($autohash,['name','hobbies'],['Moe',['go','chess']]);

# alias $autohash to regular hash for more concise hash notation
use Hash::AutoHash qw(autohash_alias);
my %hash;
autohash_alias($autohash,%hash);
# access or change hash elements without using ->
$hash{name}='Joe';                     # changes $autohash and %hash
my $name_via_hash=$hash{name};         # 'Joe'
my $name_via_autohash=$autohash->name; # 'Joe'
# get two elements in one statement
my($name,$hobbies)=@hash{qw(name hobbies)};

# nested structures work, too, of course
my $name=autohash_hash first=>'Joe',last=>'Doe';
my $person=autohash_hash name=>$name,hobbies=>['hiking','cooking'];
my $first=$person->name->first;    # 'Joe'

DESCRIPTION

This is yet another module that lets you access or change the elements of a hash using methods with the same name as the element's key. It follows in the footsteps of Hash::AsObject, Hash::Inflator, Data::OpenStruct::Deep, Object::AutoAccessor, and probably others. The main difference between this module and its forebears is that it supports tied hashes, in addition to regular hashes. This allows a modular division of labor: this class is generic and treats all hashes the same; any special semantics come from the tied hash.

The class has a 'new' method but also supplies several functions for constructing new Hash::AutoHash objects.

The constructor functions shown in the SYNOPSIS are all you need for typical uses. autohash_hash creates a new 'real' (ie, not tied) Hash::AutoHash object; autohash_tie creates a new tied Hash::AutoHash object. Once the objects are constructed, the class treats them the same way.

You can get the value of a hash element using hash notation or by invoking a method with the same name as the key. For example, the following are equivalent.

my $name=$autohash->{name};
my $name=$autohash->name;

You can also change the value of an element using either notation:

$autohash->{name}='Jonathan';
$autohash->name('Jonathan');

And you can add new elements using either notation:

$autohash->{first_name}='Joe';
$autohash->last_name('Plumber');

CAUTIONS

  • When using method notation, keys must be syntactically legal method names and cannot include 'funny' characters.

  • INCOMPATIBLE CHANGE: As of version 1.14, it is no longer possible to use method notation for keys with the same names as methods inherited from UNIVERSAL (the base class of everything). These are 'can', 'isa', 'DOES', and 'VERSION'. The reason is that as of Perl 5.9.3, calling UNIVERSAL methods as functions is deprecated and developers are encouraged to use method form instead. Previous versions of AutoHash are incompatible with CPAN modules that adopt this style.

Nested structures work straightforwardly. If a value is a Hash::AutoHash object, you can use a series of '->' operators to get to its elements.

my $name=autohash_hash first=>'Joe',last=>'Doe';
my $person=autohash_hash name=>$name,hobbies=>['hiking','cooking'];
my $first=$person->name->first;    # $name is 'Joe'

The class provides a full plate of functions for performing hash operations on Hash::AutoHash objects. These are useful if you want to avoid hash notation all together. The following example uses these functions to removes hash elements whose values are undefined:

use Hash::AutoHash qw(autohash_keys autohash_delete);
my @keys=autohash_keys($autohash);
for my $key (@keys) {
  autohash_delete($autohash,$key) unless defined $autohash->$key;
}

The autohash_set function is an easy way to set multiple elements at once. This is especially handy for setting the initial value of a tied Hash::AutoHash object, in cases where the tied hash cannot do this directly.

use Hash::AutoHash qw(autohash_set);
my $autohash=autohash_tie Tie::Hash::MultiValue;
autohash_set($autohash,name=>'Joe',hobbies=>'hiking',hobbies=>'cooking');

In the example above, 'hobbies' is set twice, because that's how Tie::Hash::MultiValue lets you set a multi-valued element. Setting the element to an ARRAY of values doesn't do it.

You can also feed autohash_set separate ARRAYs of keys and values.

my $autohash=autohash_tie Tie::Hash::MultiValue;
autohash_set($autohash,['name','hobbies'],['Joe','hiking']);

You can alias the object to a regular hash for more concise hash notation.

use Hash::AutoHash qw(autohash_alias);
my $autohash=autohash_tie Tie::Hash::MultiValue;
autohash_alias($autohash,%hash);
$hash{name}='Joe';                  # changes both $autohash and %hash
$autohash->hobbies('kayaking');     # changes both $autohash and %hash
my($name,$hobbies)=@hash{qw(name hobbies)};

By aliasing $autohash to %hash, you avoid the need to dereference the variable when using hash notation. Admittedly, this is a minor convenience, but the reduction in verbosity can be useful in some cases.

It is also possible to link a Hash::AutoHash object to an existing hash which may be real or tied, a process we call wrapping. The effect is similar to aliasing. The difference is that with aliasing, the object exists first whereas with wrapping, the hash exists first.

# wrap existing hash - can be real or tied.
use Hash::AutoHash qw(autohash_wrap);
my %hash=(name=>'Moe',hobbies=>['running','rowing']);
my $autohash=autohash_wrap %hash;
my($name,$hobbies)=@hash{qw(name hobbies)};
$hash{name}='Joe';                  # changes both $autohash and %hash
$autohash->hobbies('kayaking');     # changes both $autohash and %hash

If the Hash::AutoHash object is tied, the autohash_tied function returns the object implementing the tied hash. If the Hash::AutoHash object is aliased to a hash, the function also works on the hash. autohash_tied is almost equivalent to Perl's built-in tied function; see "Accessing the tied object" for details.

use Hash::AutoHash qw(autohash_tied);
my $autohash=autohash_tie Tie::Hash::MultiValue;
my $tied=autohash_tied($autohash);  # Tie::Hash::MultiValue object 
autohash_alias($autohash,%hash);
my $tied=autohash_tied(%hash);      # same object as above

If you're certain the Hash::AutoHash object is tied, you can invoke methods on the tied object as follows. CAUTION: this will generate an error if the object is not tied.

my $result=autohash_tied($autohash)->some_method(@parameters);

A safer way is to supply the method name and parameters as additional arguments to the autohash_tied function. This will return undef if the object is not tied.

my $result=autohash_tied($autohash,'some_method',@parameters);

Keeping the namespace clean

Hash::AutoHash provides all of its capabilities through class methods (these are methods, such as 'new', that are invoked on the class rather than on individual objects) or through functions that must be imported into the caller's namespace. In most cases, a method invoked on an object is interpreted as a request to access or change an element of the underlying hash.

CAUTION: As of version 1.14, it is not possible to use method notation for keys with the same names as methods inherited from UNIVERSAL (the base class of everything). These are 'can', 'isa', 'DOES', and 'VERSION'. The reason is that as of Perl 5.9.3, calling UNIVERSAL methods as functions is deprecated and developers are encouraged to use method form instead. Previous versions of AutoHash are incompatible with CPAN modules that adopt this style.

Special care is needed with methods used implicitly by Perl to implement common features ('import', 'AUTOLOAD', 'DESTROY').

'import' is usually invoked by Perl as a class method when processing 'use' statements to import functions into the caller's namespace. We preserve this behavior but when invoked on an object, we interpret the call as a request to access or change the element of the underlying hash whose kye is 'import'.

'AUTOLOAD' and 'DESTROY' pose different problems, since they are logically object methods. Fortunately, Perl leaves enough clues to let us tell whether these methods were called by Perl or directly by the application. When called by Perl, they operate as Perl expects; when called by the application, they access the underlying hash.

The 'new' method warrants special mention. In normal use, 'new' is almost always invoked as a class method, eg,

new Hash::AutoHash(name=>'Joe')

This invokes the 'new' method on Hash::AutoHash which constructs a new object as expected. If, however, 'new' is invoked on an object, eg,

$autohash->new

the code accesses the hash element named 'new'.

Constructors

Hash::AutoHash provides a number of constructor functions as well as a 'new' method which is simply a front-end for the constructor functions. To use the constructor functions, you must import them into the caller's namespace using the common Perl idiom of listing the desired functions in a 'use' statement.

use Hash::AutoHash qw(autohash_hash autohash_tie autohash_wrap autohash_wrapobj
                      autohash_wraptie autohash_new);

autohash_hash

Title   : autohash_hash
Usage   : $autohash=autohash_hash name=>'Joe',hobbies=>['hiking','cooking']
Function: Create a real (ie, not tied) Hash::AutoHash object and 
          optionally set its initial value
Returns : Hash::AutoHash object
Args    : Optional list of key=>value pairs

autohash_tie

Title   : autohash_tie
Usage   : $autohash=autohash_tie Tie::Hash::MultiValue
Function: Create a tied Hash::AutoHash object
Returns : Hash::AutoHash object tied to the given class
Args    : The class implementing the tied hash; quotes are optional. Any 
          additional parameters are passed to the TIEHASH constructor.

The object returned by autohash_tie is simultaneously a Hash::AutoHash object and a tied hash. To get the object implementing the tied hash (ie, the object returned by Perl's tie function), do either of the following.

my $tied=tied %$autohash;            # note '%' before '$'
my $tied=autohash_tied($autohash);   # note no '%' before '$'

The autohash_set function is a convenient way to set the initial value of a tied Hash::AutoHash object in cases where the tied hash cannot do this directly.

use Hash::AutoHash qw(autohash_set);
my $autohash=autohash_tie Tie::Hash::MultiValue;
autohash_set ($autohash,name=>'Joe',hobbies=>'hiking',hobbies=>'cooking');

In the example above, 'hobbies' is set twice, because that's how Tie::Hash::MultiValue lets you set a multi-valued element. Setting the element to an ARRAY of values doesn't do it.

You can also provide autohash_set with separate ARRAYs of keys and values.

my $autohash=autohash_tie Tie::Hash::MultiValue;
autohash_set($autohash,['name','hobbies'],['Joe','hiking']);

Wrapping an existing hash or tied object

The constructor functions described in this section let you create a Hash::AutoHash object that is linked to an existing hash or tied object, a process we call wrapping. Once the linkage is made, the contents of the object and hash will be identical; any changes made to one will be reflected in the other.

autohash_wrap

Title   : autohash_wrap
Usage   : $autohash=autohash_wrap %hash,name=>'Joe',hobbies=>['hiking','cooking']
Function: Create a Hash::AutoHash object linked to the hash. The initial
          value of the object is whatever value the hash currently has. Any
          additional parameters are key=>value pairs which are used to set
          further elements of the object (and hash)
Returns : Hash::AutoHash object linked to the hash
Args    : Hash and optional list of key=>value pairs. The hash can be real or
          tied. The key=>value pairs set further elements of the object (and 
          hash).
Notes   : If the hash is tied, the constructed object will be tied to the 
          object implementing the tied hash.  If the hash is not tied, the 
          constructed object will be tied to an object of type 
          Hash::AutoHash::dup which implements the linking.

autohash_wrapobj

Title   : autohash_wrapobj
Usage   : $autohash=autohash_wrapobj $tied_object,name=>'Joe',hobbies=>'hiking'
Function: Create a Hash::AutoHash object linked to a tied hash given 
          the object implementing the tie (in other words, the object returned
          by Perl's tie function). The initial value of the constructed object
          is whatever value the hash currently has. Any additional parameters 
          are key=>value pairs which are used to set further elements of the 
          object (and hash).
Returns : Hash::AutoHash object linked to the hash
Args    : Object implementing a tied hash and optional list of key=>value 
          pairs. The key=>value pairs set further elements of the object (and 
          hash).

Here is another, perhaps more typical, illustration of autohash_wrapobj.

$autohash=autohash_wrapobj tie %hash,'Tie::Hash::MultiValue'

You can set initial values in the constructed object by including them as parameters to the function, using parentheses to keep them separate from the parameters to 'tie'. All the parentheses in the example below are necessary.

$autohash=autohash_wrapobj ((tie %hash,'Tie::Hash::MultiValue'),
                            name=>'Joe',hobbies=>'hiking',hobbies=>'cooking')

autohash_wraptie

Title   : autohash_wraptie
Usage   : $autohash=autohash_wraptie %hash,Tie::Hash::MultiValue
Function: Create a Hash::AutoHash object linked to a tied hash and do 
          the tying in one step.
Returns : Hash::AutoHash object linked to the hash. As a side effect,
          the hash will be tied to the given class.
Args    : Hash and the class implementing the tied hash (quotes are optional).
          Any additional parameters are passed to the TIEHASH constructor.
Notes   : This is equivalent to
          $autohash=autohash_wrapobj tie %hash,'Tie::Hash::MultiValue'

new

'new' and autohash_new are front-ends to the other constructor functions. To accommodate the diversity of the other functions, the parameter syntax makes some assumptions and is not completely general.

Title   : new 
Usage   : $autohash=new Hash::AutoHash 
                        name=>'Joe',hobbies=>['hiking','cooking']
          -- OR --
          $autohash=new Hash::AutoHash ['Tie::Hash::MultiValue'],
                        name=>'Joe',hobbies=>'hiking',hobbies=>'cooking'
          -- OR --
          $autohash=new Hash::AutoHash \%hash,
                        name=>'Joe',hobbies=>'hiking',hobbies=>'cooking'
          -- OR --
          $autohash=new Hash::AutoHash $tied_object,
                        name=>'Joe',hobbies=>'hiking',hobbies=>'cooking'
          -- OR --
          $autohash=new Hash::AutoHash [\%hash,'Tie::Hash::MultiValue'],
                        name=>'Joe',hobbies=>'hiking',hobbies=>'cooking'
Function: Create a Hash::AutoHash object and optionally set elements.
          Form 1, like autohash_hash, creates a real (ie, not tied) object.
          Form 2, like autohash_tie, creates a tied object,
          Form 3, like autohash_wrap, creates an object linked to a hash.
          Form 4, like autohash_wrapobj, creates an object linked to a tied 
            hash given the object implementing the tie
          Form 5, like autohash_wraptie, creates an object linked to a tied 
            hash and does the tie in one step 
Returns : Hash::AutoHash object
Args    : The first argument determines the form. The remaining arguments are
          an optional list of key=>value pairs which are used to set elements
          of the object
          Form 1. first argument is a scalar (eg, a string)
          Form 2. first argument is an ARRAY whose elements are the class
            implementing the tied hash (quotes are required) followed by
            additional parameters for the the TIEHASH constructor.
          Form 3. first argument is a HASH that doesn't look like a tied 
            object.  See form 4.
          Form 4. first argument is a HASH that looks like a tied object; this
            is any blessed HASH that provides a TIEHASH method.
          Form 5. first argument is an ARRAY whose elements are a HASH and the 
            class implementing the tied hash (quotes are required) followed by
            additional parameters for the the TIEHASH constructor.

autohash_new

Like new, autohash_new is a front-end to the other constructor functions. We provide it for stylistic consistency. To accommodate the diversity of the other functions, the parameter syntax makes some assumptions and is not completely general.

Title   : autohash_new 
Usage   : $autohash=autohash_new name=>'Joe',hobbies=>['hiking','cooking']
          -- OR --
          $autohash=autohash_new ['Tie::Hash::MultiValue'],
                                 name=>'Joe',hobbies=>'hiking',hobbies=>'cooking'
          -- OR --
          $autohash=autohash_new \%hash,
                                 name=>'Joe',hobbies=>'hiking',hobbies=>'cooking'
          -- OR --
          $autohash=autohash_new $tied_object,
                                 name=>'Joe',hobbies=>'hiking',hobbies=>'cooking'
           -- OR --
          $autohash=autohash_new [\%hash,'Tie::Hash::MultiValue'],
                                 name=>'Joe',hobbies=>'hiking',hobbies=>'cooking'
Function: same as 'new'
Returns : Hash::AutoHash object
Args    : same as 'new'

Aliasing: autohash_alias

You can alias a Hash::AutoHash object to a regular hash to avoid the need to dereference the variable when using hash notation. The effect is similar to wrapping an existing hash via the autohash_wrap function. The difference is that with aliasing, the Hash::AutoHash object exists first and you are linking a hash to it, whereas with wrapping, the hash exists first.

Once the linkage is made, the contents of the object and hash will be identical; any changes made to one will be reflected in the other.

As a convenience, the autoahash_alias functions can link in either direction depending on whether the given object exists.

Title   : autohash_alias
Usage   : autohash_alias($autohash,%hash)
Function: If $autohash is defined and is a Hash::AutoHash object, link
          $autohash to %hash. If $autohash is not defined, create a new 
          Hash::AutoHash object that wraps %hash
Args    : Hash::AutoHash object or undef and hash 
Returns : Hash::AutoHash object

Getting and setting hash elements

One way to get and set hash elements is to treat the object as a HASH and use standard hash notation, eg,

my $autohash=autohash_hash name=>'Joe',hobbies=>['hiking','cooking'];
my $name=$autohash->{name};
my($name,$hobbies)=@$autohash{qw(name hobbies)};
$autohash->{name}='Moe';
@$autohash{qw(name hobbies)}=('Joe',['running','rowing']);

A second approach is to invoke a method with the name of the key. Eg,

$autohash->name;
$autohash->name('Moe');                   # sets name to 'Moe'
$autohash->hobbies(['blading','rowing']); # sets hobbies to ['blading','rowing']

New hash elements can be added using either notation. For example,

$autohash->{first_name}='Joe';
$autohash->last_name('Plumber');

If the object wraps or aliases a hash, you can operate on the hash instead of the Hash::AutoHash object. This may allow more concise notation by avoiding the need to dereference the object repeatedly.

use Hash::AutoHash qw(autohash_alias);
autohash_alias($autohash,%hash);
my $name=$hash{name};		# instead of $autohash->{name}
my @keys=keys %hash;          # instead of keys %$autohash

The class also provides two functions for wholesale manipulation of arguments. To use these functions, you must import them into the caller's namespace using the common Perl idiom of listing the desired functions in a 'use' statement.

use Hash::AutoHash qw(autohash_get autohash_set);

autohash_get

Title   : autohash_get
Usage   : ($name,$hobbies)=autohash_get($autohash,qw(name hobbies))
Function: Get values for multiple keys.
Args    : Hash::AutoHash object and list of keys
Returns : list of argument values

autohash_set

Title   : autohash_set
Usage   : autohash_set($autohash,name=>'Joe Plumber',first_name=>'Joe')
          -- OR --
          autohash_set($autohash,['name','first_name'],['Joe Plumber','Joe'])
Function: Set multiple arguments in existing object.
Args    : Form 1. Hash::AutoHash object and list of key=>value pairs
          Form 2. Hash::AutoHash object, ARRAY of keys, ARRAY of values
Returns : Hash::AutoHash object

Functions for hash-like operations

These functions provide hash-like operations on Hash::AutoHash objects. These are useful if you want to avoid hash notation all together. To use these functions, you must import them into the caller's namespace using the common Perl idiom of listing the desired functions in a 'use' statement.

use Hash::AutoHash 
   qw(autohash_clear autohash_delete autohash_each autohash_exists 
      autohash_keys autohash_values 
      autohash_count autohash_empty autohash_notempty);

autohash_clear

Title   : autohash_clear
Usage   : autohash_clear($autohash)
Function: Delete entire contents of $autohash
Args    : Hash::AutoHash object
Returns : nothing

autohash_delete

Title   : autohash_delete
Usage   : autohash_delete($autohash,@keys)
Function: Delete keys and their values from $autohash.
Args    : Hash::AutoHash object, list of keys
Returns : nothing

autohash_exists

Title   : autohash_exists
Usage   : if (autohash_exists($autohash,$key)) { ... }
Function: Test whether key is present in $autohash.
Args    : Hash::AutoHash object, key
Returns : boolean

autohash_each

Title   : autohash_each
Usage   : while (my($key,$value)=autohash_each($autohash)) { ... }
          -- OR --
          while (my $key=autohash_each($autohash)) { ... }
Function: Iterate over all key=>value pairs or all keys present in $autohash
Args    : Hash::AutoHash object
Returns : list context: next key=>value pair in $autohash or empty list at end
          scalar context: next key in $autohash or undef at end

autohash_keys

Title   : autohash_keys
Usage   : @keys=autohash_keys($autohash)
Function: Get all keys that are present in $autohash
Args    : Hash::AutoHash object
Returns : list of keys

autohash_values

Title   : autohash_values
Usage   : @values=autohash_values($autohash)
Function: Get the values of all keys that are present in $autohash
Args    : Hash::AutoHash object
Returns : list of values

autohash_count

Title   : autohash_count
Usage   : $count=autohash_count($autohash)
Function: Get the number keys that are present in $autohash
Args    : Hash::AutoHash object
Returns : number

autohash_empty

Title   : autohash_empty
Usage   : if (autohash_empty($autohash)) { ... }
Function: Test whether $autohash is empty
Args    : Hash::AutoHash object
Returns : boolean

autohash_notempty

Title   : autohash_notempty
Usage   : if (autohash_notempty($autohash)) { ... }
Function: Test whether $autohash is not empty. Complement of autohash_empty
Args    : Hash::AutoHash object
Returns : boolean

Accessing the tied object: autohash_tied

If a Hash::AutoHash object is tied, the application sometimes needs to access the object implementing the underlying tied hash. The term 'tied object' refers to this object. This is necessary, for example, if the tied object provides options that affect the operation of the tied hash.

In many cases, you can access the tied object using Perl's built-in tied function.

my $autohash=autohash_tie Tie::Hash::MultiValue;
my $tied=tied %$autohash;             # note leading '%'

However Perl's built-in tied function doesn't do the right thing when the Hash::AutoHash object wraps or is aliased to a regular (not tied) hash. In these cases, the code uses an internal tied hash to implement the connection between the Hash::AutoHash object and the hash. (The internal tied hash is currently named Hash::AutoHash::alias, but this is subject to change).

The autohash_tied function is a safer way to get the tied object. In most cases, it is equivalent to Perl's built-in tied function, but it reaches through the internal Hash::AutoHash::alias object when one is present.

If the Hash::AutoHash object is aliased to a hash, the function also works on the hash.

use Hash::AutoHash qw(autohash_tied);
my $autohash=autohash_tie Tie::Hash::MultiValue;
my $tied=autohash_tied($autohash);  # Tie::Hash::MultiValue object 
autohash_alias($autohash,%hash);
my $tied=autohash_tied(%hash);      # same object as above

If you're certain the Hash::AutoHash object is tied, you can invoke methods on the result of autohash_tied. This will generate an error if the object is not tied. A safer way is to supply the method name and parameters as additional arguments to the autohash_tied function. This will return undef if the object is not tied.

 # two ways to invoke method on tied object
 # 1st generates error if $autohash not tied
 # 2nd returns undef if $autohash not tied
 my $result=autohash_tied($autohash)->some_method(@parameters);
 my $result=autohash_tied($autohash,'some_method',@parameters);

use Hash::AutoHash qw(autohash_tied);

Title   : autohash_tied 
Usage   : $tied=autohash_tied($autohash)
          -- OR --
          $tied=autohash_tied(%hash)
          -- OR --
          $result=autohash_tied($autohash,'some_method',@parameters)
          -- OR --
          $result=autohash_tied(%hash,'some_method',@parameters)
Function: The first two forms return the object implementing the tied hash that
          underlies a Hash::AutoHash object if it is tied, or undef if it isn't
          tied.  The latter two forms invoke a method on the tied object if the
          Hash::AutoHash object is tied, or undef if it isn't tied. 
          In forms 1 and 3, the first argument is the Hash::AutoHash object.
          In forms 2 and 4, the first argument is a hash to which a 
          Hash::AutoHash object has been aliased
Returns : In forms 1 and 2, object implementing tied hash or undef.
          In forms 3 and 4, result of invoking method (which can be anything or
          nothing), or undef.
Args    : Form 1. Hash::AutoHash object
          Form 2. hash to which Hash::AutoHash object is aliased
          Form 3. Hash::AutoHash object, method name, optional list of
            parameters for method
          Form 4. hash to which Hash::AutoHash object is aliased, method name,
            optional list of parameters for method

Subclassing

Special considerations apply when subclassing Hash::AutoHash due to its goal of keeping the namespace clean and its heavy use of functions instead of methods.

A common use-case is a subclass that provides an object interface to a specific tied hash class. In such cases, the subclass would probably provide a 'new' method that constructs objects tied to that class and would probably want to hide the other constructor functions. The subclass might also want to provide the other functions from Hash::AutoHash (why not?) but might want to change their names to be consistent with the subclass's name.

Here is an example subclass, TypicalChild, illustrating this use-case. TypicalChild provides a 'new' method that creates objects tied to Tie::Hash::MultiValue. The 'new' method can also set the object's initial value (the TIEHASH method of Tie::Hash::MultiValue does not support this directly). The subclass provides the other functions from Hash::AutoHash but renames each from autohash_XXX to typicalchild_XXX.

package TypicalChild;
use Hash::AutoHash;
our @ISA=qw(Hash::AutoHash);
our @NORMAL_EXPORT_OK=();
our %RENAME_EXPORT_OK=();
our @RENAME_EXPORT_OK=sub {s/^autohash/typicalchild/; $_};
our @EXPORT_OK=TypicalChild::helper->EXPORT_OK;
our @SUBCLASS_EXPORT_OK=TypicalChild::helper->SUBCLASS_EXPORT_OK;

#############################################################
# helper package to avoid polluting TypicalChild namespace
#############################################################
package TypicalChild::helper;
use Hash::AutoHash qw(autohash_tie autohash_set);
use Tie::Hash::MultiValue;
BEGIN {
  our @ISA=qw(Hash::AutoHash::helper);
}
sub _new {
  my($helper_class,$class,@args)=@_;
  my $self=autohash_tie Tie::Hash::MultiValue;
  autohash_set($self,@args);
  bless $self,$class;
}
1;

The subclass consists of two packages: TypicalChild and TypicalChild::helper. The helper package is where all the real code goes to avoid polluting TypicalChild's namespace. TypicalChild must be a subclass of Hash::AutoHash (ie, Hash::AutoHash must be in its @ISA array); TypicalChild::helper must be a subclass of Hash::AutoHash::helper (ie, Hash::AutoHash::helper must be in its @ISA array).

The 'new' method of Hash::AutoHash dispatches to the '_new' method in the helper class after making sure the method was invoked on a class. That's why the code has a '_new' method in TypicalChild::helper rather than 'new' method in TypicalChild.

The BEGIN block is needed to make sure @ISA is set at compile-time before @EXPORT_OK is calculated.

The code in TypicalChild dealing with the various EXPORT_OK arrays handles the renaming of functions from Hash::AutoHash (or, more generally, any ancestor class), the exporting of additional functions defined by the subclass, and sets the stage for subclasses of the subclass to do the same thing.

Variable: @NORMAL_EXPORT_OK
Usage   : @NORMAL_EXPORT_OK=qw(autohash_set typicalchild_function)
Function: Functions that will be exported 'normally', in other words with no 
          change of name. The functions can be defined here (in the helper 
          class, not the main class!!) or in any ancestor class

Variable: %NORMAL_EXPORT_OK
Usage   : %NORMAL_EXPORT_OK=(learn=>'autohash_set',forget=>'autohash_delete')
Function: Functions that will be exported with a different name. The left-hand 
          side of each pair is the new name; the right-hand side is the name of
          a function defined here (in the helper class, not the main class!!) 
          or in any ancestor class

Variable: @RENAME_EXPORT_OK
Usage   : @RENAME_EXPORT_OK=sub {s/^autohash/typicalchild/; $_}
          -- OR --
          @RENAME_EXPORT_OK=(sub {s/^autohash/typicalchild/; $_},
                             qw(autohash_exists autohash_get))
Function: Functions that will be exported with a different name. This provides
          an easy way to rename many functions at once. The first element of 
          the list is a subroutine that will be applied to each other element
          of the list to generate the new names. The functions in the list can 
          be defined here (in the helper class, not the main class!!) or in any
          ancestor class

          If the list of functions is empty, the subroutine is applied to 
          everything in its parent classes' @SUBCLASS_EXPORT_OK array.

          The form of the subroutine is exactly as for Perl's grep and map 
          functions. 

Variable: @EXPORT_OK
Usage   : @EXPORT_OK=TypicalChild::helper->EXPORT_OK
          -- OR --
          @EXPORT_OK=qw(learn forget)
Function: Complete list of functions that the subclass is willing to export. 
          The EXPORT_OK method computes this from the other variables. You can
          also set it explicitly.

Variable: @SUBCLASS_EXPORT_OK
Usage   : @SUBCLASS_EXPORT_OK=TypicalChild::helper->SUBCLASS_EXPORT_OK
          -- OR --
          @SUBCLASS_EXPORT_OK=qw(learn forget)
Function: Functions that subclasses of this class might want to export. This 
          provides the default list of functions for @RENAME_EXPORT_OK in these
          subclasses. The SUBCLASS_EXPORT_OK method simply sets this to 
          @EXPORT_OK which is tantamount to assuming that subclasses may want 
          to export everything this class exports.  You can also set it 
          explicitly.

SEE ALSO

perltie and Tie::Hash present background on tied hashes.

Hash::AsObject, Hash::Inflator, Data::OpenStruct::Deep, and Object::AutoAccessor are similar classes and may be better choices if you don't need or want to used tied hashes. The source code of Hash::AsObject alerted us to the danger of methods inherited from UNIVERSAL.

Hash::AutoHash::Args, Hash::AutoHash::MultiValued, Hash::AutoHash::AVPairsSingle, Hash::AutoHash::AVPairsMulti, Hash::AutoHash::Record are subclasses each of which provides an object interface to a specific tied hash class.

Tie::Hash::MultiValue is a nice tied hash class used as an example throughout this POD.

Many interesting tied hash classes are available on CPAN and can be found by searching for 'Tie::Hash'.

AUTHOR

Nat Goodman, <natg at shore.net>

BUGS AND CAVEATS

Please report any bugs or feature requests to bug-hash-autohash at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Hash-AutoHash. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

Known Bugs and Caveats

  • Overridden UNIVERSAL methods no longer supported

    INCOMPATIBLE CHANGE: As of version 1.14, it is no longer possible to use method notation for keys with the same names as methods inherited from UNIVERSAL (the base class of everything). These are 'can', 'isa', 'DOES', and 'VERSION'. The reason is that as of Perl 5.9.3, calling UNIVERSAL methods as functions is deprecated and developers are encouraged to use method form instead. Previous versions of AutoHash are incompatible with CPAN modules that adopt this style.

  • Tied hashes and serialization

    Many serialization modules do not handle tied variables properly, and will not give correct results when applied to Hash::AutoHash objects that use tied hashes. In this context, "serialization" refers to the process of converting Perl data structures into strings that can be saved in files or elsewhere and later restored.

    Storable handles tied hashes correctly and can be used to serialize all kinds of Hash::AutoHash objects.

    Data::Dumper, YAML,and Data::Dump::Streamer do not handle tied hashes correctly and cannot be used to serialize Hash::AutoHash objects that use tied hashes. This includes objects created by the autohash_tie, autohash_wrap, and autohash_wrapobj functions (or by equivalent calls to 'new' or autohash_new). It also includes objects that have been aliased. The only Hash::AutoHash objects that can be serialized by these packages are real ones (ie, objects created by autohash_hash or equivalent calls to 'new' or autohash_new) that have not been aliased.

    If you want to print Hash::AutoHash objects for debugging or testing purposes, Data::Dump works fine. However there is no way to recreate the objects from the printed form.

  • Tied hashes and prototypes considered harmful (by some)

    This class uses tied hashes and subroutine prototypes, Perl features that Damian Conway urges programmers to avoid. Obviously, we disagree with Damian on this point, but we acknowledge the weight of his argument.

SUPPORT

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

perldoc Hash::AutoHash

You can also look for information at:

COPYRIGHT & LICENSE

Copyright (c) 2008, 2009 Institute for Systems Biology (ISB). All Rights Reserved.

This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.