If perl is invocation by reference, why is this happening?

I read that perl uses call-by-reference when executing routines. I made a simple piece of code to test this property, but it behaves as if perl was the default:

$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 leads to the following output:

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

      

If the arguments were processed by a callback method, shouldn't x be equal to x1 and y equal to y1?

0


source to share


3 answers


To change values ​​outside of sub, you will need to change the values @_

.

The following sub interchange

makes the values ​​change:

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 result:



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

      

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

But, quoting the article:

You can see that the function may have affected the @array variable in the main program. This is generally considered bad programming practice because it does not isolate what the function does from the rest of the program.

+3


source


Perl is always definitely referenced by reference. You are declaring ($x1, $y1) = @_

copying the original argument values, since @_ contains aliases to the original parameters.

From the perlsub manpage:



Any arguments passed are displayed in the @_ array. Therefore, if you call a function with two arguments, they will be stored in $ [0] and $ [1]. The @_ array is a local array, but its elements are aliases for real scalar parameters. In particular, if the $ _ [0] element is updated, the corresponding argument is updated (or an error is raised if it is not updatable).

+8


source


I'm just getting started with Perl, and I believe you are misunderstanding what you are passing to a subroutine. When you pass $ x and $ y, you are passing the scalars $ x and $ y. You need to explicitly pass a reference that is also a scalar (the only thing ever allowed to pass to subroutines). I understand where you came from thinking that this is a call by reference, as for arrays and hashes, as you need to pass references to them.

This code should do what you are 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 am passing references to $ x and $ y using \ $ x and \ $ y. Then I use $$ x and $$ y to dereference them inside the subroutine.

-2


source







All Articles