Modification of a read-only value attempted - why?

T

Tony Lawrence

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.
 
B

Brian McCauley

Tony said:
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 };
 
A

anno4000

Tony Lawrence said:
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
 
T

Tony Lawrence

Tony Lawrence said:
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

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?
 
A

anno4000

Tony Lawrence said:
Tony Lawrence said:
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

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.

$_ 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
 
T

Tony Lawrence

Tony Lawrence said:
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

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.

$_ 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

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top