2

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?

Marco Lavagnino
  • 1,140
  • 12
  • 31
  • 3
    Please use [strict](http://perldoc.perl.org/strict.html), use [warnings](http://perldoc.perl.org/warnings.html), get comfortable with [lexically scoped variables](http://perldoc.perl.org/perlsub.html#Private-Variables-via-my()), and don't invoke subroutines with a leading `&` unless [you know why you want to do this and need to do so](http://perldoc.perl.org/perlsub.html#Prototypes). The sooner you do the happier you'll be. :) – pilcrow Jun 05 '14 at 15:59
  • Also, there are [easier ways to swap values](http://stackoverflow.com/a/18606254/132382). – pilcrow Jun 05 '14 at 16:06

3 Answers3

8

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).

pilcrow
  • 56,591
  • 13
  • 94
  • 135
marlowe
  • 81
  • 5
4

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.

AntonH
  • 6,359
  • 2
  • 30
  • 40
-2

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.

DDP
  • 137
  • 7