Common causes:
Treating a loop variable as an lvalue
In this example $x is aliased to the constant '1', so when the loop body attempts to increment $x an error is triggered. See Lists With Constant Values for more details.for my $x (1,2) { $x++; }
In all of these examples $_ is aliased to a constant, and when the loop body attempts to modify $_ an error is triggered. See Lists With Constant Values for more details.for (1,2) { chomp; } for ("foo", @list) { s/foo/bar/; } @array = map { $_++ } (1,2); @array = grep { $_++ } (1,2);
Modifying elements of @_ directly allows you to modify the variable that was passed to the function. For example, in the above example $n is now 2. But an error will occur when a constant is passed, as in the second call.sub incr { $_[0]++; } my $n = 1; incr($n); # good incr(1); # bad
It is permissible (but ill-advised) to modify $a and $b within sort. However, modifying a constant that is aliased to $a or $b is still an error.@array = sort { $a++ } (1,2);
The variables $a and $b are aliased to each item in the list being sorted, and as such modifying them is possible - but will cause an error if the current element is unmodifiable. A common cause of this is sorting an array of references when where the list has a gap. In this situation $a will be undef, and autovivification by dereferencing will trigger an error.my @bad; $bad[0] = [1]; $bad[2] = [2]; @bad = sort {$a->[0] <=> $b->[0]} @bad;
This example will cause an error because the for loop aliases $_ to the literal '1', and then calls prompt_user which attempts to read a line from STDIN and store it in $_ - which is still aliased to '1'.for (1,2) { my $data = prompt_user(); } sub prompt_user { print "Enter a number\n"; while (<STDIN>) { # Do stuff } }
The error will also occur in this simplified scenario:
for (1,2) { while (<STDIN>) { } }
And the following are safe:$_++ for (1,2); $_++ for (1,@array); @array = map {$_++} (1,@array);
my @array = (1,2); for (@array) { $_++; }
For an explanation of lists versus arrays I recommend the following:my ($x,$y) = (1,2); for ($x,$y) { $_++; }
For: | Use: | ||
& | & | ||
< | < | ||
> | > | ||
[ | [ | ||
] | ] |