5

I know the subroutine in perl pass arg by reference. But in the below code, the foreach loop in the subroutine should not be changing the value for @list because the my $i should be creating a new lexically scope var $i. Any assignment to $i should be lexically scope but not changing the @list value.

Can anyone explain what is happening inside the foreach loop that causes the value change to @list?

sub absList {    
    foreach my $i (@_) {
        $i = abs($i);
    }
}

@list = (-2,2,4,-4);
absList(@list);
print "@list";

Outputs:

2 2 4 4

2 Answers 2

5

$i is aliased to elements of @_ array due foreach feature (and @_ elements are aliased to elements of the @list due @_ magic).

From perldoc

If any element of LIST is an lvalue, you can modify it by modifying VAR inside the loop. Conversely, if any element of LIST is NOT an lvalue, any attempt to modify that element will fail. In other words, the foreach loop index variable is an implicit alias for each item in the list that you're looping over.

If you want to avoid such behavior, don't iterate directly over @_ array, ie.

sub absList {
    my @arr = @_;
    foreach my $i (@arr) {
        $i = abs($i);
    }
}
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for the links to the info. So it means that $i in foreach will always be referenced/aliased to the @arr regardless I am using it with/without my. And if the @arr is the special variable @_, it means that $i will be the actual value of the elements in @_. Assigning any value to $i means changing the value of the elements in $@. Am I right?
@user2763829 yes, my defines only the scope for iteration variable.
Thanks. Even without my in foreach, the $i will always scoped within the foreach loop as the $i will be scope locally. So is there actually a need to declare the my to $i (in this scenario or any other scenario)?
@user2763829 if you use strict which is recommended, then you have to declare $i anyway somewhere, and perl best practice is to limit the scope of every variable to smallest block in which it is actually used. Which leads to foreach my $i (..)
Or: sub absList { foreach my $i (@_) { my $j = abs($i); ... } }
2

$i here refers the list elements which it gets from @_, that's why changing $i causes change in respective list element.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.