While trying to understand how refp’s solution for random hash value selection works, I noticed something strange.
With repeated calls to the following Perl script, I consistently found that the first result returned was the same. The subsequent values returned were random:
use strict;
use warnings;
use 5.010;
my %hash = map { $_ => ord $_ } 'a' .. 'z';
say( (@_=%hash)[1|rand@_] ) for 1 .. 10; # First value always 119
Interestingly, the following does not suffer from this issue:
sub random_value { ( @_ )[ 1 | rand @_ ] }
say random_value %hash for 1 .. 10; # First value is random
Removing the references to @_ also remedies the problem:
say( (%hash)[1|rand keys %hash] ) for 1 .. 10; # First value is random
This has been tested on Windows (ActivePerl 5.14.2).
On the surface, it looks like setting @_ has something to do with it, but I’m not sure. Can anyone shed some light on what’s happening here?
EDIT
I thought this question was answered until refp provided an update. Why does the arrayref form not suffer from the same issue discussed above? :
[@_=%hash]->[1|rand@_] for 1 .. 10; # First value is random
I suspect there is a race condition where
@_is not defined in the first loop iteration.Will become
It escapes
warningsbecause@_is a predeclared variable. As you will notice:Will crash and burn because
@ais not defined in the postscript.Update:
Is not any different. It is still bad practice to use a variable in the same statement that you assign it. The difference, I am guessing, is that the precedence is somewhat altered, so that the assignment is evaluated first.