[Rio-pm] Perl 5.10 e Hash::Util::FieldHash

breno breno em rio.pm.org
Terça Março 25 09:04:02 PDT 2008


Abaixo, artigo da PerlTips. Aos programadores de plantão, uma
pergunta: embora o autor comente o uso do tão falado Class::Std (do
Conway) e do Object::InsideOut (do Hedden), ele cita o
Hash::Util::FieldHash como uma ótima alternativa. Pessoalmente nunca
usei o Object::InsideOut, mas o Class::Std parece mais um framework de
OO (como o Moose - embora nunca tenha usado o Moose) do que qualquer
outra coisa. Mesmo sendo do Conway, tenho certo receio em relação a
performance por todas as coisas que rolam por debaixo dos panos, e
pelo fato de não ser core. Já o Hash::Util::FieldHash me pareceu uma
solução muito mais "Perlish", pq permite a criação de objetos
inside-out de forma simples, preguiçosa e sem preocupações de DESTROY
(contra vazamento) ou CLONE (para multithreading). E agora é core.

Qual a percepção de vcs?

[]s

-b


==== Perl 5.10 and Hash::Util::FieldHash ====

   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 at our Perl tip at
   <http://perltraining.com.au/tips/2006-03-31.html>.

   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:

   *   A reference can be used directly as a hash key.

   *   This reference will alter itself appropriately if the process forks,
       spawns a new thread, or otherwise causes the reference to relocate
       in memory.

   *   Our hash key is considered a *weak reference*, meaning that if the
       only use of our reference is inside ``fieldhash'' structures, then
       the entire key/value pair will be garbage collected. This provides
       for automatic destruction of any objects that fall out of scope.

   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?perl5100delta>.
   To learn more about ``Hash::Util::FieldHash'' read
   <http://search.cpan.org/perldoc?Hash::Util::FieldHash>.

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


Mais detalhes sobre a lista de discussão Rio-pm