in reply to Re^5: Why does exists cause autovivication?
in thread Why does exists cause autovivication?

Thanks, but again we are tripping over semantics. I get how autovivication works, etc. I am just wondering what has higher precedence in the interpreter.

So, using my original example . . .

next LASTLOG unless exists $user_by_uid{$uid}->{$host};

. . . what does 'exists' receive? Has $user_by_uid{$uid} already been autovivified? Or does it get autovivified within the code for 'exists'? Or some intermediate phase (e.g. code that handles passing parameters to subroutines)? Where "code" refers to the code used to implement perl.

Update: Wanted to add that I apologize for any confusion. I just find it curious that in the process of testing if something exists something may be created. It seems very counter-intuitive (even if it does make sense in the broader context of dereferencing and autovivication).

And Happy New Year!!

Replies are listed 'Best First'.
Re^7: Why does exists cause autovivication?
by demerphq (Chancellor) on Jan 02, 2008 at 11:01 UTC

    Exists checks to see that the lookup of $var->{$key} is successful, meaning that $key has been used to store a value in the hash prior to the check. Thus we have:

    # $user_by_uid{$uid}->{$host} $var= $user_by_uid{$uid} $key= $host

    What this means is that if the result of $user_by_uid{$uid} is undef (either by having an explicit undef value or by not being in the %user_by_uid hash at all) then it is autovivified. If there is a hash reference stored in $user_by_uid{$uid} (either intentionally or via autoviv) then the it is checked to see if $host had ever been used as a key.

    Tring to reduce this to a one liner: exists checks the the last hash lookup you feed it, not if the full "path" through the data structure exists. This is more obvious if you consider $user_by_id[$uid]->{$host}, obviously exists doesnt operate on arrays, and we get no error, so it means that only ->{$host} part is relevent to exists.

    You could always write a simple routine:

    sub my_exists { my ($hash_ref,$key)= @_; return $hash_ref and exists $hash_ref->{$key} }

    which would not autovivify. Compare it to how the real thing *might* be coded. Im pretty sure this actually wont work due to some subtleties of hash lookups and lvalue arguments but its pretty close to the real thing.

    sub my_fake_exists { my ($hash_ref,$key)=@_; $hash_ref={} if not defined $hash_ref; #fake autoviv return exists $hash_ref->{$key}; # do the lookup }
    ---
    $world=~s/war/peace/g

      Okay, so is my original example:
      next unless exists $user_by_uid{$uid}->{$host};

      more like the following:

      $href = defined $user_by_uid{$uid} ? $user_by_uid{$uid} : {}; #Fake au +toviv next unless exists $href->{$host};

      Or would it be more like the following, using your example code?

      next unless my_fake_exists $user_by_uid{$uid}, $host;

      In other words, since there is no short-circuit evaluation to avoid the -> in my original example does that mean the autoviv occurs before anything is passed in to 'exists'?

      Thanks very much for taking time to respond and hope you had a Happy New Year!!

        No need to autovivify anything, only to test an empty hashref for a non-existent key.
        next unless exists $user_by_uid{$uid}; next unless exists $user_by_uid{$uid}->{$host};

        should do.

        --shmem

        _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                      /\_¯/(q    /
        ----------------------------  \__(m.====·.(_("always off the crowd"))."·
        ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}