Tie::AliasHash(3pm)

πŸ“¦
version 1.02 Β· 2 versions
, in ubuntu resolute, ubuntu stonking

✨ Tie::AliasHash ✨

okay bestie, buckle up, because this is Tie::AliasHash from the User Contributed Perl Documentation β€” a hash where several keys can share one single value. multiple keys, one value, it's giving polycule but make it data structures πŸ’–


🌸 NAME 🌸

Tie::AliasHash β€” hash with aliases key, aka multiple keys, one value. literally what it says on the tin, no cap.


πŸŽ€ SYNOPSIS πŸŽ€

use Tie::AliasHash;

tie %hash, 'Tie::AliasHash';

$hash{ 'foo', 'bar' } = 'baz';

print $hash{foo}; # prints 'baz'
print $hash{bar}; # prints 'baz' too

$hash{bar} = 'zab'; # $hash{foo} is changed too
print $hash{foo}; # prints 'zab'

see how foo and bar are just… the same vibe? iconic. πŸ’…


πŸ¦‹ DESCRIPTION πŸ¦‹

Tie::AliasHash creates hashes that can have multiple keys for a single value. which means some keys are literally just 'aliases' for other keys. not me making bar the understudy of foo.

the example in the synopsis up there makes a key foo and an alias key bar. those two share the same value, so fetching either one always returns the same thing, and storing a value in one of them changes both of them. they're soulmates, fr fr.

the only difference between the two keys is that bar does not get reported by keys() and each():

use Tie::AliasHash;
tie %hash, 'Tie::AliasHash';
tied(%hash)->add_alias( 'foo', 'bar' );
foreach $k (keys %hash) { print "$k\n"; } # prints 'foo'

to get the 'real' keys and the aliases together, use the allkeys function:

use Tie::AliasHash;
tie %hash, 'Tie::AliasHash';
tied(%hash)->add_alias( 'foo', 'bar' );
foreach $k (tied(%hash)->allkeys) { print "$k\n"; } # prints 'foo' and 'bar'

you can create alias keys with 3 methods:

  • pre-declaring them while tieing the hash

the tie constructor accepts an optional list of key names and aliases. the synopsis is:

tie %HASH, 'Tie::AliasHash',
  KEY => ALIAS,
  KEY => [ALIAS, ALIAS, ALIAS, ...],
  ...
  • explicitly with the add_alias method
tied(%hash)->add_alias( KEY, ALIAS );
tied(%hash)->add_alias( KEY, ALIAS, ALIAS, ALIAS, ... );
  • implicitly with a multiple-key hash assignement
$hash{ KEY, ALIAS } = VALUE;
$hash{ KEY, ALIAS, ALIAS, ALIAS, ... } = VALUE;

the list of keys and aliases can be either an array reference, eg.:

$hash{ [ 'foo', 'bar', 'baz' ] } = $value;
$hash{ \@foobarbaz } = $value;

or an explicit list, eg.:

$hash{ qw(foo bar baz) } = $value;
$hash{ @foobarbaz } = $value;
⚠️ be warned bestie: with the last example, Perl uses the $; variable (or subscript separator), which defaults to '\034' (ASCII 28). this can cause problems if you plan to use keys with arbitrary ASCII characters. always use the first form when in doubt. consult perlvar for more information. πŸ™ˆ

πŸ’œ EXPORT πŸ’œ

none by default. you can optionally export the allkeys function into your main namespace, so that it can be used like the builtin keys.

use Tie::AliasHash 'allkeys';
tie %hash, 'Tie::AliasHash';
foreach $k (allkeys %hash) { print "$k\n"; }

but see CAVEATS below for important information about allkeys. yes, it's a whole thing. iykyk.

🧚 METHODS 🧚

  • add_alias( KEY, ALIAS, [ALIAS, ALIAS, ...] ) β€” add one or more ALIAS for KEY. if KEY itself is an alias, the aliases are added to the real key which KEY points to. yes, it follows the chain, main character behaviour ✨
  • aliases( KEY ) β€” returns a list of all the aliases defined for KEY. if KEY itself is an alias, returns the real key pointed by KEY, as well as any other alias (thus excluding KEY itself) it has.
  • allkeys β€” returns all the (real) keys of the hash, as well as all the aliases. the full guest list πŸ’–
  • is_alias( KEY ) β€” returns true if the specified KEY is an alias, false otherwise (either if KEY does not exists in the hash, or it is a real key).
  • is_key( KEY ) β€” returns true if the specified KEY is a real key, false otherwise (either if KEY does not exists in the hash, or it is an alias for another key).
  • remove( KEY ) β€” remove KEY from the hash: if KEY is a real key, it is removed with all its aliases. if KEY is an alias, only the alias is removed. this is different from the builtin delete, see CAVEATS below. sneaky difference, stay woke.
  • remove_alias( ALIAS ) β€” removes the specified ALIAS from its real key. ALIAS is no longer an alias and can be assigned its own value. the real key which ALIAS used to point to is left unchanged. it's giving conscious uncoupling.
  • remove_aliases( KEY ) β€” removes all the aliases defined for KEY.
  • remove_jolly( ) β€” removes the 'jolly' key from the hash. operations on non-existant keys are restored to normality. back to business as usual πŸŽ€
  • set_jolly( KEY ) β€” sets the 'jolly' key to KEY. when you set a jolly key, all fetch and store operations on non-existant keys will be done on KEY instead.

πŸ’€ CAVEATS πŸ’€

this module can generate a wonderful amount of confusion if not used properly. the package should really have a big 'HANDLE WITH CARE' sticker on it. genuinely. other than paying special attention to what you're doing, you should be aware of the following subtlenesses:

  • transitivity

aliases are 'transitive', and always resolve to their aliased key. this means that if you write:

use Tie::AliasHash;
tie %hash, 'Tie::AliasHash';
tied(%hash)->add_alias( 'foo', 'bar' );
tied(%hash)->add_alias( 'bar', 'baz' );

$hash{baz} is created as an alias for $hash{foo}, not for $hash{bar} (which isn't a real key). this also means that if you later change $hash{bar} to point to something else, you haven't changed $hash{baz}:

tied(%hash)->add_alias( 'gup', 'bar' );
# $hash{bar} is now really --> $hash{gup}
# $hash{baz} is still      --> $hash{foo}
  • delete

the builtin delete function resolves aliases to real keys, so it deletes everything even when called on an alias:

use Tie::AliasHash;
tie %hash, 'Tie::AliasHash';
tied(%hash)->add_alias( 'foo', 'bar' );

delete $hash{bar}; # deletes $hash{foo} too!
😭 to delete an alias leaving its key intact, use the remove_alias method instead:
use Tie::AliasHash;
tie %hash, 'Tie::AliasHash';
tied(%hash)->add_alias( 'foo', 'bar' );

tied(%hash)->remove_alias( 'bar' ); # $hash{foo} remains intact
  • exists

the builtin exists function returns true on aliases too:

use Tie::AliasHash;
tie %hash, 'Tie::AliasHash';
tied(%hash)->add_alias( 'foo', 'bar' );

print exists $hash{'foo'}; # TRUE
print exists $hash{'bar'}; # TRUE

to distinguish between aliases and real keys, use the is_key method:

print exists $hash{'foo'} and tied(%hash)->is_key('foo'); # TRUE
print exists $hash{'bar'} and tied(%hash)->is_key('bar'); # FALSE
  • allkeys

if you export allkeys into your main namespace, it can be used as the builtin keys in the following code:

use Tie::AliasHash 'allkeys';
tie %hash, 'Tie::AliasHash';
foreach $key (allkeys %hash) { print "$key\n"; }

but note that allkeys is always a function call, so this does not work as you expect:

foreach $key (sort allkeys %hash) { print "$key\n"; }

you have to fool sort, or it will use allkeys as its sort routine. this can be done by providing an explicit sort routine, or forcing the result of allkeys to be interpreted as an array by referencing-dereferencing it, or with a two-step operation where you first assign allkeys to an array, and then operate on it:

foreach $key (sort { $a cmp $b } allkeys %hash) { print "$key\n"; }
foreach $key (sort @{[ allkeys %hash ]}) { print "$key\n"; }

@allkeys = allkeys %hash;
foreach $key (sort @allkeys) { print "$key\n"; }
  • the 'jolly' key

the most potentially confusing feature of this module is the 'jolly' key. when you set a value for it, all 'unknown' keys become aliases for the jolly key. this means that you can't create new keys in the hash, because if a key does not exists, the value will be 'redirected' to the jolly key. it's giving black hole but cute 🌈

we make an example of how this works and for what can be useful. suppose you have a table of records with a 'city' field. you want to count the occurrencies for Rome, Paris and London (possibly expressed in different languages), and count every other city as 'Other'.

tie %cities, 'Tie::AliasHash';

$cities{['Rome', 'Roma', 'Rom']} = 0;
$cities{['Paris', 'Parigi']} = 0;
$cities{['London', 'Londra', 'Londres']} = 0;
$cities{'Other'} = 0;
tied(%cities)->set_jolly('Other');

while($city = get_city()) {
    $cities{$city}++;
}
foreach $city (sort keys %cities) {
    print "$city:\t$cities{$city}\n";
}

a possible output for the above script can be:

London: 4
Other:  92
Paris:  7
Rome:   16

also note that the use of the jolly key is limited to fetch and store, it does not affect other hash operations, like exists, delete, each, keys and values. so it stays in its lane πŸ’…


πŸ“œ HISTORY πŸ“œ

  • v1.02 (11 Mar 2016) β€” moved to github, using Build.PL instead of Makefile.PL, added license.
  • v1.01 (26 Jun 2003) β€” fixed a bug in the EXISTS sub, now works as documented (thanks wk)
  • v1.00 (07 Mar 2001) β€” first released version
  • v0.01 (20 Feb 2001) β€” original version; created by h2xs 1.20 with options
-CAXn Tie::AliasHash

πŸ‘‘ AUTHOR πŸ‘‘

Aldo Calpini <dada@perl.it>


okay that's the whole lore 🫢 this page came to you courtesy of perl v5.40.0, dated 2024-10-13, and yeah it's literally titled Tie::AliasHash(3pm) β€” go forth and alias responsibly bestie, you ate πŸ’–βœ¨πŸŽ€

πŸ“¦ where this page comes from