Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Are "$hash{$_} ||= 1 + keys %hash" and variants well defined or not?

by demerphq (Chancellor)
on Jan 12, 2006 at 20:59 UTC ( [id://522808]=perlmeditation: print w/replies, xml ) Need Help??

Should the following two lines of code do the same thing?

$hash{$_} ||= 1 + keys %hash for @list; $hash{$_} = $hash{$_} || 1 + keys %hash for @list;

IMO the second one should be well defined. tye and diotalevi think that both are undefined, I could be conviced about the first, but I need more convincing on the second.

This came up because I was being cheeky in Re^3: Perl one-liner to remove duplicate entries from PATH and wound up scratching my head.

use Data::Dump::Streamer; my (%hash,%mash); @list=('A'..'C'); $hash{$_} ||= 1 + keys %hash for @list; $mash{$_} = $mash{$_} || 1 + keys %mash for @list; Dump(\%hash,\%mash)->Names('*hash','*mash')->Out(); __END__ %hash = ( A => 2, B => 3, C => 4 ); %mash = ( A => 1, B => 2, C => 3 );
---
$world=~s/war/peace/g

Replies are listed 'Best First'.
Re: Are "$hash{$_} ||= 1 + keys %hash" and variants well defined or not?
by bart (Canon) on Jan 12, 2006 at 21:44 UTC
    Your results do not surprise me. I personally think of these two as equivalent:
    $hash{foo} ||= keys %hash;
    for($hash{foo}) { $_ ||= keys %hash; }
    At least, the results agree: the hash element exists (hence, it is counted in keys), before the assignment is called. My rule of thumb is: if you use a hash element as a R/W L-value, then it'll autovivify. It'll even autovivify in the for loop, if the loop body is empty:
    for($hash{foo}) { } # results in { 'foo' => undef }

    I was surprised to see an exception when using a hash element as a sub parameter:

    sub blackbox { ... } blackbox($hash{foo});
    may or may not autovivify $hash{foo}, depending on what blackbox() does. For example:
    sub blackbox { } # no autovivify
    sub blackbox { $_[0] = 123 } # results in { 'foo' => 123 }

    Tested with perl 5.8.7

Re: Are "$hash{$_} ||= 1 + keys %hash" and variants well defined or not?
by xdg (Monsignor) on Jan 12, 2006 at 22:11 UTC
    $hash{$_} ||= 1 + keys %hash for @list; $hash{$_} = $hash{$_} || 1 + keys %hash for @list;

    Hmmm. I thought it was a precedence issue. Expanding slightly:

    for ( @list ) { $hash{$_} ||= ( 1 + keys %hash ); } for ( @list ) { $hash{$_} = ( $hash{$_} || ( 1 + keys %hash ) ); }

    I get why the second one works -- the (1 + keys %hash) evaluates first due to precedence, resulting at first in 1 + 0 = 1. Etc.

    But I'm surprised at the first one, given the low precedence of assignment. It seems as if the shortcut check is happening first (with higher precedence), to see if the rest of the expression is even worth evaluating and thus autovivifying before the addition happens. (An optimization bug?)

    I take that back. I'm forgetting the short-circuit. As I pondered this, the key isn't created in the hash until an assignment happens. Semantically, it looks like this is happening:

    $hash{$_} ||= 1 + keys %hash; # looks more like: ( $hash{$_} = $hash{$_} ) || ( $hash{$_} = 1 + keys %hash )

    -xdg

    Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

Re: Are "$hash{$_} ||= 1 + keys %hash" and variants well defined or not?
by whio (Beadle) on Jan 13, 2006 at 11:18 UTC
    The simplest expression of this form is probably

    $hash{foo} ||= exists $hash{foo};

    versus

    $hash{foo} = $hash{foo} || exists $hash{foo};

Re: Are "$hash{$_} ||= 1 + keys %hash" and variants well defined or not?
by zshzn (Hermit) on Jan 12, 2006 at 21:08 UTC
    I don't see specifically why it shouldn't. At first look one would assume they would do the same thing, having it otherwise appears to be illogically and prone to cause issues for unsuspecting programmers.

      I've updated it to show the results I get... You will probably be surprised.

      ---
      $world=~s/war/peace/g

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://522808]
Front-paged by kutsu
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (6)
As of 2024-03-19 09:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found