Modification of a read-only value attempted
The most common cause for this error is that perl attempted to write
to a variable that is currently aliased to a constant.
The magic of $_ is often involved.
Possible causes:
Using magical $_ behaviour in non-trivial cases
The magical properties of $_ are great for saving a few keystrokes,
but should be limited to use in small, strictly local blocks.
In this example the for loop is iterating over the
literal values '1' and '2', aliasing $_ to them.
When the inner while loop reads a line from STDIN, it assigns the value to $_. This triggers the read-only error, because at this time $_ is the literal 1.
for (1,2) {
while (<STDIN>) {
}
}
This error frequently occurs at a distance because a subroutine called within the loop modifies an unlocalized $_.
Treating a list as an array
The difference between a list and an array is often ignored, which can cause problems when modifying $_.
The intent in the following example is to iterate over two string literals, chomp the newline, and output the text:
for ("foo\n", "bar\n") {
chomp;
print;
}
This causes the read-only error to occur, because within the context of that loop $_ is aliased to the string literal "foo\n".
Note that the problem is with the modification of the string literal. It is not directly related to $_. The error occurs with this as well:
for my $str ("foo\n", "bar\n") {
chomp $str;
print $str;
}
map and
grep are common sources for this problem as well.
@bad = map {$_++} (1,2);
@bad = grep {$_++} (1,2);
Modifying @_ elements inside a subroutine
In this example the
bad() subroutine attempts
to modify the first parameter directly, using $_[0].
This causes problems if a literal value is passed.
sub bad {
$_[0]++;
}
bad(1);
Modifying $a or $b inside sort
It is permissible (but ill-advised) to modify $a and $b within sort. (Tested for perl 5.6.2, 5.8.2, and 5.8.4)
my @good = (1,2);
@good = sort {$a++ <=> $b} @good;
However, modifying a literal that is assigned to $a or $b
is still an error.
@bad = sort {$a++ <=> $b} (1,2);
Dereferencing $a or $b inside a sort block without testing that they are references
Very closely related to the previous problem is the issue of dereferencing $a or $b
when you do not know that they exist and are a reference. If $a is undefined and
you attempt to use it as an array reference, perl will attempt to autovivify $a
as an arrayref, which modifies the readonly value. Splode.
my @bad;
$bad[0] = [1];
$bad[2] = [2];
@bad = sort {$a->[0] <=> $b->[0]} @bad;
Guidelines to avoid this error:
- Don't modify an unlocalized $_
- Don't modify $_ inside of map
- Don't modify $a or $b inside sort
- Don't dereference $a or $b inside sort without checking that they are references
- Don't use $_ for the loop variable unless it is a very trivial loop
- Don't modify elements of @_ directly