Modification of a read-only value attempted - why?

19 views
Skip to first unread message

Tony Lawrence

unread,
Sep 15, 2006, 12:37:09 PM9/15/06
to
Can someone explain this to me?

(full text at http://aplawrence.com/Unix/perl_readonly.html ,
abbreviated version here)

Test code:

#!/usr/bin/perl -w
# no problem here
caroomba("first");


@dayval=qw(foo ba);
foreach $dayval (@dayval) {
# no problem here
caroomba($dayval);
}


foreach $dayval ("foo2","ba2") {
# no problem here either
caroomba($dayval);
}


foreach ("foo3","ba3") {
# doesn't like this
$dayval=$_;
caroomba($dayval);
}

sub caroomba {
my $p=shift;
print "Caroomba called $p\n";
open(I,"./t");
while (<I>) {
# stuff..
}
close I;
}


When run, that produces:


Caroomba called first
Caroomba called foo
Caroomba called ba
Caroomba called foo2
Caroomba called ba2
Caroomba called foo3 Modification of a read-only value attempted at
./t.pl line 23, <I> line 23.

Why?

Something to do with anonymous arrays, but I don't grok it.

Brian McCauley

unread,
Sep 15, 2006, 1:08:31 PM9/15/06
to

Tony Lawrence wrote:
> Can someone explain this to me?
>
> (full text at http://aplawrence.com/Unix/perl_readonly.html ,
> abbreviated version here)
>
> Test code:

[still rather long ]

I've abberviated your example to:

for ("foo3") {
while (<DATA>) {
}
}
__END__

The <> construct in a while() performs an implicit assignment to the
global variable $_ but does _not_ perform an implicit local($_) in the
way for() does.

The for() makes the global variable $_ an alias for the readonly value
"foo3".

> Something to do with anonymous arrays, but I don't grok it.

No, nothing to do with arrays.

The obvious, but _wrong_ solution is to insert local($_) before the
while(<...>). This will work 99.99% of the time but that last time in
10000 $_ will be aliased to an element of a tied agregate (HASH or
ARRAY) and then local($_) will do evil things.

The correct fix is either to local(*_) or to avoid the implicit
assignment feature completely.

Note that an unfortunate side effect of local(*_) is that is localizes
@_ etc too. You can get arround this with the rather peverse looking
code...

local(*_) = do{ \my $underscore };

anno...@radom.zrz.tu-berlin.de

unread,
Sep 15, 2006, 1:13:55 PM9/15/06
to
Tony Lawrence <pcu...@gmail.com> wrote in comp.lang.perl.misc:

> Can someone explain this to me?
>
> (full text at http://aplawrence.com/Unix/perl_readonly.html ,
> abbreviated version here)
>
> Test code:

[snip code that doesn't show the problem]

> foreach ("foo3","ba3") {
> # doesn't like this
> $dayval=$_;
> caroomba($dayval);
> }
>
>
>
> sub caroomba {
> my $p=shift;
> print "Caroomba called $p\n";
> open(I,"./t");
> while (<I>) {
> # stuff..
> }
> close I;
> }
>
>

> Caroomba called foo3 Modification of a read-only value attempted at
> ./t.pl line 23, <I> line 23.
>
> Why?
>
> Something to do with anonymous arrays, but I don't grok it.

Which anonymous array? I don't see any.

The problem is the nesting (through a sub call) of the outer
for-loop and the inner while-loop. The outer "for" aliases $_
to the read-only literal "foo3". This alias is still in effect
inside the sub. The while-loop now tries to use the variable
$_ as its implicit variable. Since $_ is aliased to a read-only
value, that fails with the error you see.

Anno

Tony Lawrence

unread,
Sep 16, 2006, 5:57:03 AM9/16/06
to

OK, I see it now. If the subroutine is modified to add

print "\$_ is $_\n";

it shows up quickly:

..
Use of uninitialized value in concatenation (.) or string at ./t.pl
line 21.
$_ is
Caroomba called ba2
$_ is foo3
Caroomba called foo3
Modification of a read-only value attempted at ./t.pl line 24.

I never realized that $_ would be passed down to a subroutine.. I
thought the sub would have its own $_.. but there it is.

So.. this isn't considered a bug or flaw in Perl? This is intended
behavior?

anno...@radom.zrz.tu-berlin.de

unread,
Sep 16, 2006, 6:26:32 AM9/16/06
to

$_ is a package variable. It is the same whenever you access it.

> So.. this isn't considered a bug or flaw in Perl? This is intended
> behavior?

It's expected behavior.

Anno

Tony Lawrence

unread,
Sep 16, 2006, 12:19:36 PM9/16/06
to

Ayup. I see it now, thanks. The Camel book actually tells you that
the default variable for angle bracket input is the global $_ and not
the local $_ (p.81 of the 3rd edition, otherwise look for the section
on Line Input (Angle) Operator).

I'm sure I read that at least once, but the significance escaped me -
thanks again.

Michele Dondi

unread,
Sep 19, 2006, 10:45:59 AM9/19/06
to
On 16 Sep 2006 10:26:32 GMT, anno...@radom.zrz.tu-berlin.de wrote:

>$_ is a package variable. It is the same whenever you access it.
>
>> So.. this isn't considered a bug or flaw in Perl? This is intended
>> behavior?
>
>It's expected behavior.

It may be interesting to mention that bleadperl provides both a
lexical $_ and means to use it in constructs that resort on $_. I only
gave a quick peek into those features quite a lot of time ago and I
can't remember the details offhand, though...


Michele
--
{$_=pack'B8'x25,unpack'A8'x32,$a^=sub{pop^pop}->(map substr
(($a||=join'',map--$|x$_,(unpack'w',unpack'u','G^<R<Y]*YB='
.'KYU;*EVH[.FHF2W+#"\Z*5TI/ER<Z`S(G.DZZ9OX0Z')=~/./g)x2,$_,
256),7,249);s/[^\w,]/ /g;$ \=/^J/?$/:"\r";print,redo}#JAPH,

Reply all
Reply to author
Forward
0 new messages