Tie::Ha...lyStack(3)
π Tie::Hash::ReadonlyStack β user contributed Perl documentation, bestie π
okay so you found a .3 page in the User Contributed Perl Documentation section and it's literally called Tie::Hash::ReadonlyStack and it is SO much better than the name suggests, I promise. sit down, grab a strawberry, we're doing this. π
β¨ NAME β¨
Tie::Hash::ReadonlyStack β treat multiple hashes as a single hash, and do not modify the original hashes when you assign values. no cap. that's the whole vibe. π
π¦ VERSION π¦
This doc describes Tie::Hash::ReadonlyStack version 0.2. vintage but iconic. π
πΈ SYNOPSIS πΈ
use Tie::Hash::ReadonlyStack;
# %defaults could be a readonly hash, maybe from something like this: Readonly::Hash my %defaults => ( ... );
# or maybe you just want to modify some values without blowing away a global default
my $tie_obj = tie my %config, 'Tie::Hash::ReadonlyStack', \%defaults;
# load up any server specific configuration we have
$tie_obj->add_lookup_override_hash('local', \%server_specific_hash);
# when we determine the user:
$tie_obj->add_lookup_override_hash('user', \%user_specific_hash);
# when we go to run a given context:
$tie_obj->add_lookup_fallback_hash('context', \%context_specific_hash);
# look for 'frobnigate' in %user_specific_hash, %server_specific_hash, %defaults, %context_specific_hash
# returning the value of the first found, lets say it's current value is 1 which is inside %server_specific_hash
if ($config{'frobnigate'}) {
$config{'frobnigate'} += 5; # %server_specific_hash (actually, all of the hash's above) remains unchanged
print $config{'frobnigate'};
# this prints '6' ,
# the tied hash '%config' holds the new value, the value is unchanged in the hashes making up %config
}
# context is ending so clean up:
$tie_obj->delete_lookup_hash('context');
...
undef $tie_obj; # untie() caveat!
untie %config
lowkey poetry tbh. the 'frobnigate' thing going from 1 to 6 while the originals stay untouched?? that's the whole personality of this module. π«Ά
π DESCRIPTION π
So the tie you get from this module has 2 main behaviors. two. count them. π₯
First: it treats a stack of hashes as a single unit, kinda like Tie::Proxy::Hash β except without the "translation" mechanism and with some other differences. (iykyk.)
This means you get to have your main hash, and then you assign other hashes to be searched for a given key either before or after that main hash. cute, right?
Peep the "SYNOPSIS" for an example of exactly that. β¨
Second: it lets you use hashes that are readonly inside said stack without fatal errors. this is the part that saves lives. π
For example, say you (ironically enough) have a hash made via Readonly. If you try to assign to it:
Readonly::Hash my %readonly => ( ... );
$readonly{'key'} = 'value'; # throws "Modification of a read-only value attempted at ..."
or say you have a GDBM_File file tied in readonly mode:
tie my %gdbm, 'GDBM_File', 'data.gdbm', &GDBM_READER, 0640;
$gdbm{'key'} = 'value'; # throws "gdbm store returned -1, errno 0, key "key" at ..."
print $gdbm{'key'}; # never gets here
print $gdbm{'abc'};
You could wrap those assignments in an eval, but not only is that cluttered β the value is unchanged anyway (which is sort of what "readonly" means ;p).
Putting that hash into a Tie::Hash::ReadonlyStack hash lets you assign new values without modifying the hash it came from. slay.
tie my %gdbm, 'GDBM_File', 'data.gdbm', &GDBM_READER, 0640;
tie my %data, 'Tie::Hash::ReadonlyStack', \%gdbm;
$data{'key'} = 'value';
print $data{'key'}; # prints 'value'
print $data{'abc'}; # prints the value of 'abc' from the database
But wait β besides the whole "storing a new value won't trigger fatal errors on various sorts of readonly type hashes" thing, there's another benefit: π
Sometimes a hash key's value is used to calculate a new value, and then that new value gets re-stored as a cacheing mechanism.
For example, with a Locale::Maketext Lexicon hash: a key is looked up, compiled into an internal form, and re-stored as a reference β typically a SCALAR or CODE. Template::ToolKit can do similar behavior. If your tied hash stored the new value in your database, then the next time it's used you'd probably get something like 'SCALAR(0x800ab0)' or 'CODE(0x800ab0)' instead of the string you expected. absolutely not. π
In short, keeping all new values internally as part of the 'Tie::Hash::ReadonlyStack' is a good thing because it:
- keeps the orignal hashes unmodified (i.e. does not stomp on things you might not want stomped on) π«Ά
- will make readonly hashes not fatal when values are changed π
- allow values to be changed for local pruposes (i.e. as part of a calculate-then-cache mechanism) β¨
π¦ INTERFACE π¦
This is just a normal tie(). The only argument after the name space is the single "main" hash.
tie my %hash, ' Tie::Hash::ReadonlyStack', \%main_hash;
Others can be added or removed via the methods outlined below. π
π tie object methods π
You get the tie object as the return value of tie() and tied()
my $tie_obj = tie my %hash, 'Tie::Hash::ReadonlyStack', \%main_hash;
or
tie my %hash, ' Tie::Hash::ReadonlyStack', \%main_hash;
...
my $tie_obj = tied(%hash);
If you use the tie object, make sure you clean it up before untie()
(i.e. this is the untie() caveat mentioned in pretty much every tie related document, see "OBLIGATORY UNTIE CAVEAT")
undef $tie_obj; # untie() caveat, undef any references before you untie it!
untie %hash;
π add_lookup_override_hash()
Adds the hash to the stack before the "main" one.
$tie_obj->add_lookup_override_hash('identifier',\%hash);
It will not add the "main" hash or an already existing one. If you want to replace a hash you must del_lookup_hash() first. periodt.
If %hash is not tied then this happens:
$tie_obj->clear_compiled_cache(keys %hash)
If it is tied (since keys() could possibly have a lot of wasted overhead *) then the new hash is checked for the existence of each compiled key, which is deleted from the cache if it exists.
If this behavior is undesireable with your tied hash you can call "add_lookup_override_hash_without_clearing_cache()" and handle the cache however you need to via "clear_compiled_cache()"
* Imagine it is tied to aDB_Filewith ten million keys.keys()andeach()would be very expensive for no advantage... π
πΈ add_lookup_override_hash_without_clearing_cache()
Same as add_lookup_override_hash() except with out the cache clearing behavior. bestie it does what it says on the tin. β¨
π«Ά add_lookup_fallback_hash()
Adds the hash to the stack after the "main" one.
$tie_obj->add_lookup_fallback_hash('identifier',\%hash);
It will not add the "main" hash or an already existing one. If you want to replace a hash you must del_lookup_hash() first. (yes, same rule as the override one, no shortcuts. π
)
π del_lookup_hash()
Remove the hash from the stack and remove any of its values that are in the cache
$tie_obj->del_lookup_hash('identifier')
Returns false if you try to remove the "main" hash. not the main character, can't delete it. π€
By default it won't do an exists() check β this is good because it will clean up any dangling bits leftover by bad manual intervention (but you wouldn't do that would you ;p).
To make it return false when the hash being delted does not exist, give it a second true argument:
# assuming $only_if_exists is true:
if (!$tie_obj->del_lookup_hash('identifier', $only_if_exists)) {
print "The given hash isn't part of the stack, that sure is weird...";
}
else {
print "The given hash has been removed from the stack";
}
π¦ clear_compiled_cache()
This method empties the cache or un-caches a given list of keys.
$tie_obj->clear_compiled_cache(); # remove all cached values
The 'no argument' form returns 1.
$tie_obj->clear_compiled_cache('foo','bar'); # remove 'foo' and 'bar' from the cache
The 'list of keys arguments' form returns the number of keys actually deleted, or false if none of the given keys existed (and hence nothing was deleted). no notes. π₯
β get_keys_not_in_stack()
This returns a list of keys that were used but were not found in any of the hashes in the stack.
That happens when you assign a value to a key that does not exist in any of the hashes in the stack:
$hash{'new_key'} = 42; # $tie_obj->get_keys_not_in_stack() would now include 'new_key'
delete $hash{'new_key'}; # $tie_obj->get_keys_not_in_stack() would no longer include 'new_key'
it's giving β¨bookkeepingβ¨ and honestly we love that for it.
π hash behavior π
fetching a value (e.g. using the $hash{'key'} or exists()) will:
- look in the cache to see if we have it already
- if the key is not in the cache it looks for the key in each hash in the stack of hashes in the proper order
- if we're fetching the value: in the first hash it exists in it will cache it and use that
Assigning a value will add the key and fetched value to the cache (i.e. not to any of the hashes in the stack)
each(), keys(), values(), etc operate on tha cache of values you've accessed and assigned.
That means that if you are tied to a database with ten million keys via a hash that gets them from the DB on demand instead of loading them all up at once, and have only referenced 5, then your working hash has 5 keys. efficiency ate. π
If you delete() a key it deletes it from the cache but not from hashes in the stack. important. remember it. π«Ά
π©Ί DIAGNOSTICS π©Ί
Throws no errors or warnings itself. silence. iconic. π€«
βοΈ CONFIGURATION AND ENVIRONMENT βοΈ
Tie::Hash::ReadonlyStack requires no configuration files or environment variables. zero setup, we love a low-maintenance queen. π
π¦ DEPENDENCIES π¦
None. β¨
π« INCOMPATIBILITIES π«
None reported. π
π BUGS AND LIMITATIONS π
No bugs have been reported. (suspiciously flawless but ok π)
Please report any bugs or feature requests to "bug-tie-hash-readonlystack@rt.cpan.org", or through the web interface at <http://rt.cpan.org>.
π OBLIGATORY UNTIE CAVEAT π
See "The "untie" Gotcha "</cyan> in perltie or <cyan>"The "untie" Gotcha"</cyan> in perltiedepending on if the perdoc you get sent to has the broken-by-extra-space'The untie Gotcha'` header. (the drama of documentation, honestly. π)
Note that this module doesn't (currently) define a destructor so we should be fine. π«Ά
π SEE ALSO π
Tie::Proxy::Hash, perltie
π TODO π
- review for efficiency improvements, especially memory π§
- ? consider mechanism to mark certain hashes as "update this hash's value instead of the cache" ? π
- review for additional tests, perhaps of object's structure and state at various points ? π§ͺ
π AUTHOR π
Daniel Muey "<http://drmuey.com/cpan_contact.pl>" β the main character who wrote this. π
β LICENCE AND COPYRIGHT β
Copyright (c) 2009, Daniel Muey "<http://drmuey.com/cpan_contact.pl>". All rights reserved.
This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See perlartistic.
π DISCLAIMER OF WARRANTY π
okay bestie, deep breath, because this is the part where the lawyers took the keyboard π and it's giving very serious, but we're reading it together because it genuinely matters and I refuse to let you skip it π
so: because this software is licensed free of charge, there is NO WARRANTY for it β and we mean that to the absolute fullest extent that applicable law even permits us to say it. that's the whole vibe. π
except when somebody states otherwise in writing, the copyright holders and/or other parties hand you this software "AS IS", with no warranty of any kind β not expressed, not implied, none. and yes, that includes (but is so not limited to) the implied warranties of MERCHANTABILITY and FITNESS FOR A PARTICULAR PURPOSE. both of them, gone, poof, bye π¦
and here's the bit that's genuinely on you: the entire risk as to the quality and performance of the software is with you. if it turns out to be defective, you're the one footing the bill for all the necessary servicing, repair, or correction. not us. that's just the deal. π
and last one, highkey important: in no event β unless applicable law requires it, or somebody agreed to it in writing β will any copyright holder, or any other party who may modify and/or redistribute the software as the above licence permits, be liable to you for damages. we're talking general, special, incidental, or consequential damages arising out of using the software or being unable to use it. and yeah, that includes (but is not limited to) loss of data, data being rendered inaccurate, losses sustained by you or by third parties, or the software failing to operate with any other software. even if that holder or other party was literally advised of the possibility of such damages. still not liable. periodt. π
fr fr, read it again if you skimmed. it's the boring part and it's the part that counts. π
and that's the whole page, bestie!! π you made it all the way to the end and I'm so proud of you π«Ά this was Tie::Ha...lyStack(3) from the perl v5.42.0 docs, dated 2025-07-25 β now go forth and tie those hashes to a stack, you absolute icon πβ¨π
π¦ where this page comes from
- fedora 43: perl-Tie-Hash-ReadonlyStack 0.2-27.fc43 Β· GPL-1.0-or-later OR Artistic-1.0-Perl
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms