Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine

Re^5: Why does exists cause autovivication?

by demerphq (Chancellor)
on Dec 31, 2007 at 08:51 UTC ( #659724=note: print w/replies, xml ) Need Help??

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

When do the dereferencing and autovivication occur?

Autvivification occurs any time you use a variable whose value is undef as a hash or array reference in a lookup or assignment statement. Simple example:

>perl -e"my $x=undef; $y++ if $x->{foo}; print $x" HASH(0x15d56e0)

Notice how the if $x->{foo} autovivified $x into a hash reference. When you have a multiple key lookup this rule applies to each value in turn until you get to the last lookup.

This behaviour is very powerful and is used all the time in perl. About the only thing you need to keep in mind, is when doing a lookup where you care about autoviv you have to check each value for undef first. Iow:

if ($x and $x->{foo} and $x->{foo}{bar} and exists $x->{foo}{bar}{baz} +) { }

It doesn't take long to get used to working with complex perl variables and to learn strategies that minimize how often you need to do stuff like this, with experienced perl programmers only rarely having to do so.


Replies are listed 'Best First'.
Re^6: Why does exists cause autovivication?
by Argel (Prior) on Dec 31, 2007 at 19:41 UTC
    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!!

      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 }

        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!!

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://659724]
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (4)
As of 2018-03-20 01:05 GMT
Find Nodes?
    Voting Booth?
    When I think of a mole I think of:

    Results (247 votes). Check out past polls.