Question

I've read that perl uses call-by-reference when executing subrutines. I made a simple piece of code to check this property, but it behaves like if perl was call-by-value:

$x=50;
$y=70;

sub interchange {
    ($x1, $y1) = @_;

    $z1 = $x1;
    $x1 = $y1;
    $y1 = $z1;

    print "x1:$x1 y1:$y1\n";
}

&interchange ($x, $y);

print "x:$x y:$y\n";

This produces the following output:

$ perl example.pl
x1:70 y1:50
x:50 y:70

If arguments were treated in a call-by-reference way, shouldn't x be equal to x1 and y equal to y1?

Was it helpful?

Solution

To modify the values outside of the sub, you would have to modify the values of @_.

The following sub interchange does modify the values:

sub interchange {
    ($x1, $y1) = @_; # this line copies the values to 2 new variables

    $z1 = $x1;
    $x1 = $y1;
    $y1 = $z1;

    $_[0] = $x1; # this line added to change value outside sub
    $_[1] = $y1; # this line added to change value outside sub

    print "x1:$x1 y1:$y1\n";
}

This gives the output:

x1:70 y1:50
x:70 y:50

More info here: http://www.cs.cf.ac.uk/Dave/PERL/node51.html

But, to quote the article:

You can see that the function was able to affect the @array variable in the main program. Generally, this is considered bad programming practice because it does not isolate what the function does from the rest of the program.

OTHER TIPS

Perl is always definitely call by reference. You're statement ($x1, $y1) = @_ is copying the original argument values, since @_ holds aliases to the original parameters.

From perlsub manpage:

Any arguments passed in show up in the array @_ . Therefore, if you called a function with two arguments, those would be stored in $[0] and $[1] . The array @_ is a local array, but its elements are aliases for the actual scalar parameters. In particular, if an element $_[0] is updated, the corresponding argument is updated (or an error occurs if it is not updatable).

I'm just starting with Perl as well, and I believe you're misunderstanding just what you're passing to the subroutine. When you pass $x and $y you are passing the scalars $x and $y are set to. You need to explicitly pass a reference, which also happens to be a scalar (being the only thing are ever allowed to pass to subroutines). I understand where you're coming from in thinking things are call-by-reference since for arrays and hashes, since you need to pass references to those.

This code should do what you're looking for:

#!/usr/bin/perl

$x=50;
$y=70;

sub interchange {
    ($x1, $y1) = @_;

    $z1 = $$x1; # Dereferencing $x1
    $$x1 = $$y1; # Dereferencing $x1 and $y1
    $$y1 = $z1; # Dereferencing $y1

    print "x1:$$x1 y1:$$y1\n";
}

&interchange (\$x, \$y); # Passing references to $x and $y, not their values

print "x:$x y:$y\n";

I pass in references to $x and $y using \$x and \$y. Then, I use $$x and $$y to dereference them within the subroutine.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top