August 2016 Archives

Do not pass perl globals as arguments to subroutines

Recently I faced this problem when loose an exception message in Mojolicious

What do you think is wrong here

$c->helpers->reply->exception($@) unless eval { $next->(); 1 };

For first sight nothing. We eval code and then catch exception if it is and pass error into sub. But we forget that when arguments are passed into subroutine they are aliased into @_ NOT COPIED (Maybe we forgot that because of it is not documented here ) but, thanks, documented here

 The array @_ is a local array, but its elements are aliases for the actual scalar parameters.

So @_ contain aliases. What does that matter? Look please at this small example:

sub test {
  $@ =  'Oops';
  my( $x ) =  @_;
  print $x; # Oops
$@ =  'Exception';
test( $@ );

As you can see between subroutine call and arguments coping there is something may happen and change your global variable. As result you do not get the value you pass into subroutine.

As workaround this problem, I think, you should never pass globals. Take care and pass copies of them:

test( my $copy = $@ );

Aliasing hurts not only perl internal global variables that hurts every global variable:

test( my $copy = $YourPackage::variable );

Hope this small note will save your time when you wanna pass global variable into subroutine.

About KES

user-pic I blog about Perl.