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

Got this bit of code in a test:

say (exists $fs4->{_structure}{'/Users/dotfiles/perl5/my_modules'}{BLA +H}{Crap}); # BLAH and its parent do not exist d $fs4; # dumps the object

The dump of the object now shows this:

### Dump from: 01-FSO_basic.t line: 35 $VAR1 = { '/Users/dotfiles/perl5/my_modules' => { 'BLAH' => {} },

I was pretty surprised to see the path and BLAH in the output as keys. So why is 'BLAH' key getting autovivified? Second, how I work around this?

Update: This one-liner reproduces the problem for me:

perl -MData::Dump -E ' my $fs4 = {'_structure' => {}}; exists $fs4->{_ +structure}{BLAH}{TEST}{Crap}; dd $fs4->{_structure} '

Outputs:  { BLAH => { TEST => {} } }

$PM = "Perl Monk's";
$MC = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate Priest Vicar Parson";
$nysus = $PM . ' ' . $MC;
Click here if you love Perl Monks

Replies are listed 'Best First'.
Re: Perl autovivifyies object property when using exists
by choroba (Cardinal) on Apr 03, 2024 at 19:24 UTC
    > how I work around this?

    autovivification

    perl -MData::Dump -E 'no autovivification; my $fs4 = {_structure => {}}; exists $fs4->{_structure}{BLAH}{TEST}{Crap}; dd $fs4->{_structure};' {}

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      Nice. I figured there was some pragma-like way to change this behavior, but never heard of "no autovivification".
        It's worth noting that the default behavior of no autovivification doesn't disable it in case of assignments aka store

        Which is great because that's DWIM for most. But surprising given the name of the pragma...

        DB<5> no autovivification; $h->{a}{b}{c} = 42 DB<6> x $h 0 HASH(0xb400007e0b2fd8b8) 'a' => HASH(0xb400007e0b2ea7f8) 'b' => HASH(0xb400007e0b2eac30) 'c' => 42 DB<7>

        From the autovivification docs

        Possible unimports:

        • no autovivification qw<fetch store exists delete>;
        But store is not default
        • no autovivification; # defaults to qw<fetch exists delete>

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        see Wikisyntax for the Monastery

Re: Perl autovivifyies object property when using exists
by Danny (Chaplain) on Apr 03, 2024 at 19:03 UTC
    This is a pervasive gotcha in perl. You need to check the existence of any parent references whose existence you are unsure of before checking their children. Otherwise the parents will pop into existence.

      Ah, got it. Thanks. Quite the little gotcha. Never knew about this.

      $PM = "Perl Monk's";
      $MC = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate Priest Vicar Parson";
      $nysus = $PM . ' ' . $MC;
      Click here if you love Perl Monks

Re: Perl autovivifyies object property when using exists
by ikegami (Patriarch) on Apr 03, 2024 at 20:16 UTC

    Because of autovivification, $x->{ foo } means ( $x //= { } )->{ foo }.[1]

    As such,

    $fs4->{_structure}{'/Users/dotfiles/perl5/my_modules'}{BLAH}{Crap}

    means

    ( ( ( ( $fs4 //= { } )->{_structure} //= { } )->{ '/Users/dotfiles/perl5/my_modules' } //= { } )->{ BLAH } //= { } )->{ Crap }

    It has nothing to do with exists. (Notice how ->{ Crap } is not created.)

    To avoid this, you could use a whole bunch of checks, or you could use the awesome autovivification pragma module.

    no autovivification;

    1. Some conditions apply.
Re: Perl autovivifyies object property when using exists
by soonix (Chancellor) on Apr 05, 2024 at 11:42 UTC
Re: Perl autovivifyies object property when using exists
by NetWallah (Canon) on Apr 03, 2024 at 17:56 UTC
    $ perl -MData::Dump -E '$fs4={_structure=>{"/Users/dotfiles/perl5/my_ +modules"=>{}}};my $b= $fs4->{_structure}{"/Users/dotfiles/perl5/my_mo +dules"};say (exists $b->{BLAH} and exists $b->{BLAH}{crap}); say dd( +$fs4)'
    output:
    { _structure => { "/Users/dotfiles/perl5/my_modules" => {} } } 1

                    "If it happens once, it's a bug. If it happens twice, it's a feature. If it happens more than twice, it's a design philosophy."

      Oh, I see the second exists call in there now. Missed it the first time.

      $PM = "Perl Monk's";
      $MC = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate Priest Vicar Parson";
      $nysus = $PM . ' ' . $MC;
      Click here if you love Perl Monks

      This reproduces the problem:

      perl -MData::Dump -E ' my $fs4 = {'_structure' => {}}; exists $fs4->{_ +structure}{BLAH}{TEST}{Crap}; dd $fs4->{_structure} '

      Output: { BLAH => { TEST => {} } }

      $PM = "Perl Monk's";
      $MC = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate Priest Vicar Parson";
      $nysus = $PM . ' ' . $MC;
      Click here if you love Perl Monks

      I'm at a loss. I get the same as you on the command line. But in my test, running this:

      my $fs4 = {'_structure' => {}}; say (exists $fs4->{_structure}{'/Users/dotfiles/perl5/my_modules'}{BL +AH}{Crap}); d $fs4->{_structure}, 3;

      I get this:

      $VAR1 = { '/Users/dotfiles/perl5/my_modules' => { 'BLAH' => {} } };

      $PM = "Perl Monk's";
      $MC = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate Priest Vicar Parson";
      $nysus = $PM . ' ' . $MC;
      Click here if you love Perl Monks