in reply to caching hashrefs in state

Is this good practice?

I don't see anything directly wrong with it. It's just not clear to me from what you write whether some other construct might be more fitting in your situation. Maybe this is an XY Problem - what exactly are you trying to achieve by "caching" the config hashref like this? How do you want your code to behave when individual config values are changed, or the entire config is replaced?

state $cfg never gets re-initialized, so it will always refer to the same hash, and cfg_cache() will always return that same hashref. The contents of the config hash being referred to can still be freely manipulated by anyone holding a reference to the original hash (that's what you're seeing when your code prints "mouse") or anyone calling cfg_cache().

Perhaps you have over-simplified your example code a bit but I don't see the difference between your method and using a (readonly) global variable?

If you're interested in protecting the config hash against (accidental) changes, see Readonly and/or lock_keys from Hash::Util.

Replies are listed 'Best First'.
Re^2: caching hashrefs in state
by AnomalousMonk (Archbishop) on Apr 22, 2014 at 22:10 UTC

    Just to expand on what Laurent_R and Anonymonk have said, I would say the OPed question has less to do with the peculiarities of state variables than with the fecund peculiarities of references.

    From the OP:
    my $cfg = { x => "cat"};

    cfg_cache($cfg);

    When these two statements from the OPed code finish execution, there are two references to the underlying  { x => "cat" } anonymous hash object: one in the  $cfg lexical variable in the main-line code, another in the  $cfg state variable in the scope of the  cfg_cache() function. The underlying object may be accessed and changed via either reference.

    The contents of the config hash being referred to can still be freely manipulated by anyone holding a reference to the original hash (that's what you're seeing when your code prints "mouse") or anyone calling cfg_cache().

    This point deserves to be emphasized. The intent of the practice exemplified in the OPed code may be to achieve some kind of immutable data structure, but that's not the case. This can be seen from case E of the example below in which the original hash object is altered using the equivalent of cfg_cache().

    c:\@Work\Perl\monks>perl -wMstrict -le "use feature 'state'; ;; my $hashref = { x => 'cat' }; S($hashref); ;; print 'A1: ', S('trash')->{x}; print 'A2: ', $hashref->{x}; ;; $hashref->{x} = 'mouse'; print 'B1: ', S('junk')->{x}; print 'B2: ', $hashref->{x}; ;; undef $hashref; print 'C1: ', S('dreck')->{x}; print 'C2: ', $hashref->{x}; ;; $hashref = { x => 'snark' }; print 'D1: ', S('bilge')->{x}; print 'D2: ', $hashref->{x}; ;; S('cruft')->{x} = 'oliphaunt'; print 'E1: ', S('fudge')->{x}; print 'E2: ', $hashref->{x}; ;; sub S { state $ref = shift; return $ref; } " A1: cat A2: cat B1: mouse B2: mouse C1: mouse Use of uninitialized value in print at -e line 1. C2: D1: mouse D2: snark E1: oliphaunt E2: snark
    Is this good practice?

    It's always good practice to understand references if you use them. :)