in reply to Modification of a read-only value

I am guessing that this code is inside a subroutine and you're calling it while $_ is aliased to a constant. Try this:

for ( "read", "only", "value" ) { print "$_\n"; $_ = "test"; # blows up }

The problem is probably concealed in your code like so:

sub foo { $_ = "test"; } foo(); # works for ( "read", "only", "value" ) { print "$_\n"; foo(); # blows up }

The solution is to put a local $_; at some opportune point to decouple one piece of the code from the other. The trap is that aliasing constructs like for(), map and friends do not need such treatment, but while(<FH>) does.

Makeshifts last the longest.

Replies are listed 'Best First'.
Re^2: Modification of a read-only value
by Sprad (Hermit) on Aug 21, 2004 at 16:03 UTC
    Yes! This was the problem. I'm not sure how far back I'm picking up constant values, but I changed the "while (<PIPE>)" to "while ($foo = <PIPE>)" and that took care of it. Thank you!

    I didn't realize that whiles treated $_ differently. I'll watch that in the future...

    ---
    A fair fight is a sign of poor planning.

      :)

      I first saw this in a question in the monastery a long time ago. That was a far nastier case, though: someone was getting spurious action at a distance. Turns out one of his map blocks was calling a sub containing a while(<FH>), and because map aliases $_, the function modified the values in his source array. Ouch.

      Ever since, while(<FH>) used without a local has been a red flag in my mind. Always localize $_ when you use this construct. (Or use a different variable, as you did, of course.)

      Makeshifts last the longest.

      while (<PIPE>)
      is equivalent to
      while (defined($_ = <PIPE>))
      so you might want to use
      while (defined($foo = <PIPE>))
      instead of
      while ($foo = <PIPE>)
      What you are using will stop when you don't expect it (such as when you read in a blank line).

        Perl's one step ahead of you:

        $ perl -MO=Deparse -e'while($foo=<>){}' while (defined($foo = <ARGV>)) { (); } -e syntax OK

        This is a relatively recent change from two or so years ago, though; I don't rememeber which version introduced it off-hand.

        Even without the definedness test it wouldn't stop on a blank line either, btw. Don't forget the record separator. A blank line is not an empty string; it's "\n". What that construct would fail to process is the very last line of a file, if it contains only a 0 and is not terminated by a record separator. (It can't be blank, obviously, because a blank line with no record separator is, well, err, no line at all. :-))

        Makeshifts last the longest.