Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?

Method call to tied hash leads to file read error

by Cirollo (Friar)
on May 28, 2003 at 16:15 UTC ( #261350=perlquestion: print w/replies, xml ) Need Help??

Cirollo has asked for the wisdom of the Perl Monks concerning the following question:

I wrote a module using cached hashes to access methods, as in the node A cacheing tied hash base class. The point is that you can access data using things like $object->{method}. After writing a moderately sided module around this, I've come across a strange bug. Depending on the way I call the method, sometimes I get a "Modification of a read-only value" error at the end of a file read.

Here's some code that reproduces the problem. Run it with the path to a file as an argument. The first way of calling the method will read and print out every line in the file, but the second way causes a fatal error, which occurs on the last line of the file (I think).

#!/bin/perl -w package My::Module; use vars qw(@ISA); use Carp; use Tie::Hash; @ISA = qw(Tie::StdHash); sub TIEHASH { my($class) = shift; my($self) = { }; bless $self, $class; } sub FETCH { my($self, $key) = @_; unless (exists $self->{$key}) { if (my $meth = $self->can($key)) { $self->{$key} = $meth->($self); } else { warn "No method for '$key'"; $self->{$key} = undef; } } return $self->{$key}; } sub new { my($class) = shift; my(%hash); tie %hash, $class; $hash{filename} = shift; return \%hash; } sub my_method { my $self = shift; open(IN, $self->{filename}) or croak "Couldn't open file $self->{f +ilename}: $!"; while (<IN>) { print; } close IN; } 1; package main; # THIS WORKS: my $obj1 = new My::Module($ARGV[0]); my $method = 'my_method'; print $obj1->{$method}; # THIS DOESNT WORK -- error message: # Modification of a read-only value attempted at /home/apirkle/perl/bu line 41. my $obj2 = new My::Module($ARGV[0]); print $obj2->{$_} for (qw|my_method|); exit;
Any thoughts on why the second way of calling the method (in a for loop) doesn't work?

Replies are listed 'Best First'.
Re: Method call to tied hash leads to file read error
by blokhead (Monsignor) on May 28, 2003 at 16:43 UTC
    You've just experienced the joy of $_. The problem is that while (<FH>) doesn't local'ize $_. Consider this:

    You write:

    print $obj2->{$_} for (qw|my_method|);
    So now $_ is set to a read-only value. Then eventually from within that call we get to this line:
    while (<IN>) {
    ... which is syntactic sugar for:
    while (defined($_ = <IN>)) {
    You see that this line is assigning to $_ (still containing the read only 'my_method'). while didn't local'ize $_!! This is a common trap, and I know someone has written an extensive writeup about this particular trap among many CPAN modules.

    In short, put local $_; right above the while (<IN>) line, and things should work fine.


Re: Method call to tied hash leads to file read error
by broquaint (Abbot) on May 28, 2003 at 16:38 UTC
    It's because in the second instance you're looping over a constant value in the for and the trying to assign that in my_method e.g
    sub readstuff { return while <> } print readstuff for 'a constant value'; __output__ Modification of a read-only value attempted at - line 1.
    Where the while really compiles as return while defined($_ = <>). As has been mentioned before in IlyaM's while(<>) { ... } considered harmful, be careful when implicitly using $_ in subroutines and methods.


Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://261350]
Approved by Mr_Person
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (6)
As of 2022-12-01 17:31 GMT
Find Nodes?
    Voting Booth?