Perl 5.10 and Hash::Util::FieldHash

[ Perl tips index ]
[ Subscribe to Perl tips ]

Perl 5.10 adds the Hash::Util::FieldHash module to the list of core modules. Just like all of the other core modules such as File::Find and File::Temp this means that Hash::Util::FieldHash will now be installed as standard with Perl for all versions from 5.10.0 onward.

Inside-out objects and Hash::Util::FieldHash

Inside-out objects provide a method of strong encapsulation and compile-time error checking using Perl's object oriented features. This is done by keeping a separate hash for each object attribute, and using a unique identifier for the object (commonly its memory address) to access these attributes.

You can refresh your memory of inside-out objects in our previous Perl Tip.

Unfortunately, inside-out objects have two common disadvantages:

  1. Care must be taken to clean-up your attribute hashes when your object is destroyed (by going out of scope, for example). If you don't do this, you can end up leaking memory.

  2. Care must be taken when memory addresses are used as hash keys, as these addresses may change (potentially invalidating the object) when using a forked or threaded process.

When working with inside-out objects, we recommend you use a helper module like Class::Std or Object::InsideOut which can solve some or all of these problems for you. However if these modules are not suitable, or if you're working with existing code that does not use them, Hash::Util::FieldHash provides a convenient and reliable way to build inside-out objects.

Put very simply, a hash declared as a fieldhash has the following attributes:

These properties mean that we can write inside-out objects without the headaches of finding appropriate identifiers for our objects, forking/threading issues, or garbage collection. It's also possible to enable only some of the above features if we want more specific behaviour (see Further reading below).

Imagine a playing card as an object: it would have a suit and a face value (rank). We can use Hash::Util::FieldHash to simplify the creation of this as an inside-out object. A minimal class may look like this:

        package PlayingCard;
        use strict;
        use warnings;
        use Hash::Util::FieldHash qw(fieldhash);

        fieldhash my %suit_of;
        fieldhash my %rank_of;
        
        sub new {
                my ($class, $rank, $suit) = @_;
                
                # This strange looking line produces an
                # anonymous blessed scalar.
                
                my $this = bless \do{my $anon_scalar}, $class;
                
                $suit_of{ $this } = $suit;
                $rank_of{ $this } = $rank;
                
                return $this;
        }
        
        sub get_suit {
                my ($this) = @_;
                return $suit_of{ $this };
        }
        
        sub get_rank {
                my ($this) = @_;
                return $rank_of{ $this };
        }

        1;

What's interesting about this example is what's missing. We don't need a DESTROY method for memory management, nor a CLONE method for threading. By declaring %suit_of and %rank_of with fieldhash, this work is already done for us.

We could use our playing card as follows:

        #!/usr/bin/perl -w
        use strict;
        use feature qw(say);
        use PlayingCard;

        my $card = PlayingCard->new('ace', 'spades');
        say 'My rank is ', $card->get_rank;
        say 'My suit is ', $suit->get_suit;

        {
                my $card2 = PlayingCard->new('king', 'diamonds');
                say 'My new card rank is a ', $card->get_rank;
        }

$card2 will automatically be destroyed and its memory garbage collected at the end of its block.

Further reading

To find out what other modules have been included in the core read the Perl delta for 5.10.0 at http://search.cpan.org/perldoc. To learn more about Hash::Util::FieldHash read http://search.cpan.org/perldoc.

More information about Class::Std can be found at http://search.cpan.org/perldoc, and more information about Object::InsideOut can be found at http://search.cpan.org/perldoc.

[ Perl tips index ]
[ Subscribe to Perl tips ]


This Perl tip and associated text is copyright Perl Training Australia. You may freely distribute this text so long as it is distributed in full with this Copyright noticed attached.

If you have any questions please don't hesitate to contact us:

Email: contact@perltraining.com.au
Phone: 03 9354 6001 (Australia)
International: +61 3 9354 6001

Valid XHTML 1.0 Valid CSS