The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.


Tie::Proxy::Hash - Effieciently merge & translate hashes.


  my (%hash, $ref);
  $ref = tie %hash, 'Tie::Proxy::Hash', (bart   => +{a =>  1,
                                                     b =>  2},
                                         maggie => +{a =>  5,
                                                     c =>  6,
                                                     e => 10},
  $hash{a} ==  1;     # true
  $hash{b} ==  2;     # true (bart supercedes maggie)
  $hash{c} ==  6;     # true
  ! defined $hash{d}; # true
  $hash{e} == 10;     # true

  $hash{c} = 9;       # set in maggie
  $hash{d} = 12;      # set in default
  $hash{f} = 11;      # set in default

  $ref->add_hash('lisa', +{d => 3, b => 4});
  $hash{c} == 9;      # true
  $hash{b} == 2;      # true (bart overrides lisa)
  $hash{d} == 3;      # true (lisa overrides default)
  $hash{f} == 11;     # true (only default knows 'f')


Proxy hash requests for one or more other hashes, with intermediate value translation.

Tie::Proxy::Hash 'merges' hashes by maintaining a list of hashes to look up, and each key requested is looked up in each hash in order until a hit is found. Resultant values may be subject to a translating subr. In this way, hashes may be merged without the cost of by-value copying.

A default backing hash is provided to store values not present in other hashes.


 $ref = tie %hash, 'Tie::Proxy::Hash',
          bart   => +{a =>  1, b =>  2},
          maggie => +{a =>  5, c =>  6, e => 10} => sub {10*$_[0]},

Any arguments passed to tie are palmed off onto add_hash.

Retrieving Values

Values are retrieved by checking each hash in the order of insertion; the first hash found in which a given key exists supplies the value. The value is subject to translation if the given hash has an associated translator.



  $ref->add_hash('bart', +{ a => 1, b => 2 });
  $ref->add_hash('lisa', +{ c => 3, b => 4 }, sub { $_[0] * 20 });

The name by which to refer to the hash (for future manipulations, e.g., remove_hash). The name must be a valid perl identifier --- a non-empty string of word characters not beginning with a digit.

If a member with the given name already exists, the hash is updated (and the translator is updated/inserted/removed accordingly), but the order does not change. Hence, following the synopsis by calling

  $ref->add_hash('bart', +{ a => 5, b => 6 });

(without an intervening remove_hash) will set the effective value of b to 6, for the new 'bart' hash will still be checked before the 'lisa' hash.

If a member with the given name does not already exist (including if it was deleted with remove_hash), the hash is added at the end of the queue.

Hashes inserted with add_hash are always checked before the default hash, even if the default hash has values that were set prior to the named hash(es) being inserted.


The hash to add in, as a hashref. For efficiency, this hash is stored within as is. Therefore, if a reference to the same hash is manipulated externally, these manipulations will be visible to the Proxy Hash. Caveat Emptor.


Optional. If defined, all values retrieved from this hash are run through the given code ref before being returned to the caller. The subr is called with a single argument, the hash value, and is expected to return a single value (which is passed back to the caller).

The translator is only called to translate values for which keys exist in the given hash; the translator is never called to create new values.

The presence of a translator prevents any values being set in the hash (via the Tie::Proxy::Hash interface) (since there is no reverse translation facility). Therefore, if a value is set that would otherwise be stored in a translated hash, the key in that hash is deleted instead (to maintain the identity $h{c} = $x; $h{c} == $x). The storage then falls through to the next untranslated hash (possibly the default hash). This is why the default hash has no translator.

  my ($ref, %hash);
  $ref = tie %hash, 'Tie::Proxy::Hash';
  $ref->add_hash('bart', +{ a => 1, b => 2 });
  $ref->add_hash('lisa', +{ c => 3, b => 4 }, sub { $_[0] * 20 });
  $hash{c} = 5; # Sets c in the default hash, deletes 3 from lisa.

The order of calling add_hash is relevant; each hash is checked in order of insertion via add_hash. Therefore, given the example in the synopsis, the 'bart' hash is checked for values before the 'lisa' hash. Hence the effective value of b is 2.



Name of the member hash to remove. An exception will be raised if no such member exists.

Removing a hash wipes any present translation, and the named hash loses its place in the queue.




Email the author.


Martyn J. Pearce


Copyright (c) 2003 Martyn J. Pearce. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.