http://qs321.pair.com?node_id=270850

bobdeath has asked for the wisdom of the Perl Monks concerning the following question:

I know that if you have a hash, and you associate a previously undefined key in that hash with a value, that key will be automatically created and associated with whatever value you set it too. This feature, while useful at times, seems to be a major cause of bugs for me. I will either assign a key to the wrong hash, or misspell a key. I was wondering if there was a way to prevent a hash from autovivifing, or even print out a warning when it happens. I am just sick of spending 30 minutes to an hour trying to figure out what is wrong when I am not even using the autovivication feature.

Replies are listed 'Best First'.
Re: non-autovivifing hash
by particle (Vicar) on Jul 02, 2003 at 15:59 UTC

    if you're using perl 5.008, Hash::Util is in the core. you'll find the lock_keyssubroutine helpful.

    ~Particle *accelerates*

Re: non-autovivifing hash
by hardburn (Abbot) on Jul 02, 2003 at 16:00 UTC

    There's Tie::StrictHash, which has you define the hash keys and values once and then complains if you try to assign to a new key.

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    Note: All code is untested, unless otherwise stated

Re: non-autovivifing hash (not read-only keys)
by tye (Sage) on Jul 02, 2003 at 18:03 UTC

    While the read-only keys solutions (Tie::StrictHash and from Hash::Util) provide one method of preventing autovivification for hashes, they also prevent normal key creation.

    What I've long wanted was a 'no autovivify;' pragma that would prevent autovivification in the scope where it is used (for both hashes and arrays) but that would not prevent normal hash key insertion.

    I like to be able to assign new keys in the normal manner:

    $hash{key}= 'value';
    but I often prefer to not create new keys via autovivification, which is different:
    no autovivify; my %hash; # Examples of normal key insertion: $hash{key1}= 'value'; # succeeds $hash{key2}= {}; # succeeds $hash{key2}{key3}= 'value'; # succeeds # Examples of autovivification: $hash{key4}{key3}= 'value'; # should fail! $hash{key5}[0]= 1; # should fail!
    Sometimes it is very nice to be very strict in how you code. It can often find lots of bugs for you. That is why we have use strict;. Perl could really use a similar tool for optionally turning off autovivification. I'd certainly make a lot of use of it (and I've found several bugs the hard way that would have been caught quite easily if I'd had such an option).

                    - tye
Re: non-autovivifing hash
by shemp (Deacon) on Jul 02, 2003 at 16:54 UTC
    If its just a few keys that get the most usage, and sometimes get misspelled, you could consider using constants for the keys. that way, perl -c will catch and typos in the constant names. For instance:
    use constant FIRST_NAME => "first_name"; use constant LAST_NAME => "last_name"; my %some_hash = ( FIRST_NAME() => "john", LAST_NAME() => "doe", ); my $f_name = $some_hash{FRIST_NAME()}; # caught by perl -c my $f_name = $some_hash{"frist_name"}; # autovivifies ...
    I'd only use this for a few keys, in general, the other solutions offered are far superior.
Re: non-autovivifing hash
by lofichurch (Beadle) on Jul 02, 2003 at 20:02 UTC

    Why not use exists() first, before attempting to assign the value?

    Why change the underlying operation of the language, when all you have to change is your methodology?

    I find it a useful practice, that whenever I expect a certain key in a certain hash, to use exists() to verify that the key exists before attempting to read its value. exists() will NOT create a key if it does not already exist. e.g.:

    if( exists($hash{"$key"}) ) {
       print("You have \$hash{'$key'}\n");
       } else {
          print("You've messed up with \$hash and $key.\n");
          }
    

    I'd absolutely hate it if anyone ever turned off the automatic creation of keys in a hash on any of my scripts.



    !c
Re: non-autovivifing hash
by Anonymous Monk on Jul 02, 2003 at 17:32 UTC
    First of all, hash autovivification refers to assigning a key to a previously non-existant hash, not assigning a previously undefined key to an existing hash; you are indeed not using the autovivification feature. Second of all, if your problems are assigning to the wrong hash or mis-spelling a key, don't blame Perl's features which, as you say, don't even apply in this case. Why would Perl (or any programming language, really) treat assignment of a valid key to a valid hash (albeit the incorrect one) as an error? Pay more attention while you are programming! That said, this happens at some point to everyone, it's all part of the unjoy of coding/debugging.
Re: non-autovivifing hash
by toma (Vicar) on Jul 03, 2003 at 00:32 UTC
    I agree that it would be nice to have more level of control over autovivification. As tye suggests, sometimes only one level of autovivification is desired. Someone else might want at most two levels, such as when working with 2D arrays.

    A debugger could be enhanced with an object that could provide this level of checking. This debugging object would contain a pointer to a variable whose autovivification is being monitored. Perl's debugger hooks could check autovivification constraints on a line-by-line basis at run-time. After the program starts working, the run-time checking could easily be turned off.

    This is the sort of problem that I have trouble debugging with print statements, but I can easily debug with the ptkdb debugger. I just put the hash in the watch variable window and see how it grows. Or, if the data structure being monitored is too large, I put something like scalar(keys %myhash) in the watch window.

    I've already been flamed each time that I have mentioned debuggers, so maybe we can skip that part this time!

    It should work perfectly the first time! - toma