Question

I know that passing a scalar to a sub is actually passing the reference, but since I am new to perl I still did the following test:

#!/usr/bin/perl
$i = 2;
subr(\$i);
sub subr{
    print $_[0]."\n";
    print $$_[0]."\n";
}

I thought the first line is going to print an address and the second line is going to give be back the number, but the second one is a blank line. I was pointed by someone one else to do this: ${$_[0]} and it prints the number. But she didn't know the reason why without {} it is not working and why it is working with {}. So what has happened?

Was it helpful?

Solution

It's because your second print statement is equivalent to doing this...

my $x = $$_; print $x[0];

When what you want is

my $x = $_[0]; print $$x;

In other words, the de-referencing occurs before the array subscript is evaluated.

When you add those curl-wurlies, it tells perl how to interpret the expression as you want it; it will evaluate $_[0] first, and then de-reference to get the value.

OTHER TIPS

It's an order-of-evaluation thing.

  $$_[0] is evaluated as {$$_}[0]

This is the 0th element of the reference of the scalar variable $_. It's taking the reference first and then trying to find the 0th element of it.

  ${$_[0]}

This is a reference to the 0th element of the array @_. It's finding the 0th element first then taking a reference of that.

If you set use strict and use warnings at the top of your code you'll see plenty of warnings about undefined values from your first attempt.

$$_[0] is like $foo[0], only with $_ in place of the array name. This means $_ is treated as an array reference, and the expression doesn't involve the scalar reference $_[0] at all. $_->[0] is equivalent, using the alternate -> syntax. Syntax for dereferencing may seem arbitrary and hard to remember, but there is underlying sense and order; a very good presentation of it is at http://perlmonks.org/?node=References+quick+reference.

You don't have to pass a reference to $i. The notation $_[0] is an alias for $i when you invoke it as subr( $i ).

use strict;
use warnings;
use Test::More tests => 2;

sub subr{ $_[0]++ } # messing with exactly what was passed first
my $i=2;
is( $i, 2, q[$i == 2] );
subr($i);
is( $i, 3, q[$i == 3] );

Another example is this:

use strict;
use warnings;
use Test::More tests => 6;
use Test::Exception;

sub subr{ $_[0]++ }
my $i=2;
is( $i, 2, q[$i == 2] );
subr($i);
is( $i, 3, q[$i == 3] );

sub subr2 { $_[0] .= 'x'; }
dies_ok { subr2( 'lit' ); } 'subr2 *dies* trying to modify a literal';
lives_ok { 
    my $s = 'lit';
    subr2( $s );
    is( $s, 'litx', q[$s eq 'litx'] );
    subr2(( my $s2 = 'lit' ));
    is( $s2, 'litx', q[$s2 eq 'litx'] );
} 'subr2 lives with heap variables';

Output:

ok 1 - $i == 2
ok 2 - $i == 3
ok 3 - subr2 *dies* trying to modify a literal
ok 4 - $s eq 'litx'
ok 5 - $s2 eq 'litx'
ok 6 - subr2 lives with heap variables
1..6
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top