While musing and experimenting over a recent post here at the Monastery, I came across a bizarre and somewhat unexplainable behaviour of hash autovivification: a particular kind of scalar (which I dubbed a "stopper scalar" - nothing more than a silly string) would stop autovivification in its tracks, without raising any warnings or runtime errors.

At the end of the post you will find the exemplification script; below there are more detailed comments over the exemplified cases:

#!/usr/bin/perl -w use Data::Dumper; print "Case 1: non existent\n"; exists $x->{'y'}->{'z'}; print Dumper $x; print "Case 2: undef\n"; $x = undef; exists $x->{'y'}->{'z'}; print Dumper $x; print "Case 3: hashref\n"; $x = {}; exists $x->{'y'}->{'z'}; print Dumper $x; print "Case 4: stopper scalar\n"; $x = 'stopper'; exists $x->{'y'}->{'z'}; print Dumper $x; print "Case 5: Even assignment won't do, and won't trigger warning or +runtime error!\n"; $x = 'stop2'; $x->{'y'}->{'z'} = 'something'; print Dumper $x; print "Case 6: use strict is your friend :)\n"; eval { use strict 'refs'; $x = 'stop3'; $x->{'y'}->{'z'} = 'something else'; print Dumper $x; }; $@ and print $@;

And here's the output.

Case 1: non existent $VAR1 = { 'y' => {} }; Case 2: undef $VAR1 = { 'y' => {} }; Case 3: hashref $VAR1 = { 'y' => {} }; Case 4: stopper scalar $VAR1 = 'stopper'; Case 5: Even assignment won't do, and won't trigger warning or runtime + error! $VAR1 = 'stop2'; Case 6: use strict is your friend :) Can't use string ("stop3") as a HASH ref while "strict refs" in use at + ./autoviv-stop.pl line 35.

Replies are listed 'Best First'.
Re: Autovivification and soft refs
by hardburn (Abbot) on Jan 21, 2004 at 20:41 UTC

    I don't think this is worrying at all, at least not as worrying as any other use of soft references. Cases 4 and 5 end up creating a symbolic ref. Data::Dumper doesn't look at symbolic refs, although it would show the result of autovivification if you had it dump %main:: instead.

    So in truth, autovivification is occuring, but Data::Dumper isn't showing it.

    ----
    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: Autovivification and soft refs
by dragonchild (Archbishop) on Jan 21, 2004 at 20:45 UTC
    You're running into another form of autovivification. Try the modifications to your code as listed below.
    #!/usr/local/bin/perl -w use Data::Dumper; print "Case 1: non existent\n"; exists $x->{'y'}->{'z'}; print Dumper $x; print "Case 2: undef\n"; $x = undef; exists $x->{'y'}->{'z'}; print Dumper $x; print "Case 3: hashref\n"; $x = {}; exists $x->{'y'}->{'z'}; print Dumper $x; print "Case 4: stopper scalar\n"; $x = 'stopper'; exists $x->{'y'}->{'z'}; print Dumper $x; print Dumper \%{$x}; print "Case 5: Even assignment won't do, and won't trigger warning or +runtime error!\n"; $x = 'stop2'; $x->{'y'}->{'z'} = 'something'; print Dumper $x; print Dumper \%{$x}; print "Case 6: use strict is your friend :)\n"; eval { use strict 'refs'; $x = 'stop3'; $x->{'y'}->{'z'} = 'something else'; print Dumper $x; }; $@ and print $@; ---------------- Case 1: non existent $VAR1 = { 'y' => {} }; Case 2: undef $VAR1 = { 'y' => {} }; Case 3: hashref $VAR1 = { 'y' => {} }; Case 4: stopper scalar $VAR1 = 'stopper'; $VAR1 = { 'y' => {} }; Case 5: Even assignment won't do, and won't trigger warning or runtime + error! $VAR1 = 'stop2'; $VAR1 = { 'y' => { 'z' => 'something' } }; Case 6: use strict is your friend :) Can't use string ("stop3") as a HASH ref while "strict refs" in use at + ./abcd.pl line 36.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Re: Autovivification and soft refs
by Abigail-II (Bishop) on Jan 21, 2004 at 21:33 UTC
    print "Case 4: stopper scalar\n"; $x = 'stopper'; exists $x->{'y'}->{'z'}; print Dumper $x;
    What's the problem here? Perl is populating the hash %stopper, just as you ordered it to do. Replace the last line with print Dumper \%stopper and you'll see.

    Abigail

      Just add a bit of info on top of what Abigail-II said. If you my %stopper, it will stop the autovivification:

      use Data::Dumper; my %stopper; $x = 'stopper'; exists $x->{'y'}->{'z'}; print Dumper $x; print Dumper \%stopper;

      Which prints:

      $VAR1 = 'stopper'; $VAR1 = {};

      Comment out that my %stopper line, you will see the autovivification:

      $VAR1 = 'stopper'; $VAR1 = { 'y' => {} };
        If you my %stopper, it will stop the autovivification:
        Well, that would be strange. Very, very strange. Do you think that happens because there's an explicite check in perl that says "hmmm, we are doing autovivification of a secondary key in the hash, but the parent hash is a lexical, so let's not do it", or that you've hit a strange bug?

        Or could it be that autovivification is happening? And you are just giving the wrong argument to Dumper? Try giving \%{"stopper"} as argument to Dumper.

        Abigail

        Now that's interesting. Your post inspired me to dig a little deeper... it looks like the autovivification is still happening, but not on the lexical %stopper. Instead the global %::stopper is affected. Which makes sense, I suppose, because %::stopper is what was being affected in Abigail's original snippet, and with no lexical on scope, %stopper (i.e. the symbolic reference) was really referring to %::stopper. Very interesting, I certainly learned something. Thanks for pointing that out!

        use Data::Dumper; my %stopper; $x = 'stopper'; exists $x->{'y'}->{'z'}; print Dumper $x; print Dumper \%stopper; print Dumper \%::stopper;

        -- Mike

        --
        XML::Simpler does not require XML::Parser or a SAX parser. It does require File::Slurp.
        -- grantm, perldoc XML::Simpler

Re: Autovivification and soft refs
by pg (Canon) on Jan 21, 2004 at 20:38 UTC

    So I guess what you mean is that, it is important to specify 'use strict'. I do it all the time, together with 'use warnings'.

    This can tremendously improve your development and verification efficiency.

Re: Autovivification and soft refs
by ysth (Canon) on Jan 21, 2004 at 22:56 UTC
    perlref says:
    (Symbolic references are sometimes called "soft references", but please don't call them that; references are confusing enough without useless synonyms.)
    I wholeheartedly agree.

    I wish perl5.000 had bitten the bullet and outlawed symbolic refs unless you specifically said something like use symrefs;

    In some ways, use strict 'refs' doesn't fit in with use strict 'vars' or 'subs'; the latter are pretty much never a good idea. Even in a one-liner, declaring your vars or quoting your strings hardly takes any effort. But taking code that uses symbolic refs and changing it to hard refs (or symbol table manipulation via %main:: instead) takes an actual logic change.