开发者

Can anybody explain this read-only exception to me?

Below is my code (don't worry there's a USUW at the top of the module)

I'm testing if an array ref is readonly, and if that is th开发者_如何学编程e case then I'm copying it into another array ref. The tests show that the array is not read-only, yet when it runs, it fails with that error. ( For those of you not familiar with me or Smart::Comments--those ### are Smart::Comments.)

### readonly( $arg_ref ) : readonly( $arg_ref )
### readonly( @$arg_ref ) : readonly( @$arg_ref )
my @ro = map { readonly( $_ ) } @$arg_ref;
### @ro
if ( readonly $arg_ref ) {
    $arg_ref = [ @$arg_ref ];
}
return map { my $val = shift @$arg_ref;
             $_ => $val 
            } @_ 
            ;

This is the output I get:

### readonly( $arg_ref ) : 0
### readonly( @$arg_ref ) : 0

### @ro: [
###        0,
###        0,
###        0,
###        0,
###        0
###      ]

But here's the error:

Modification of a read-only value attempted at ....pm line 247.

(247 is:

return map { my $val = shift @$arg_ref;

)

Does anybody have any familiarity with this issue? We're running Perl 5.8.7. Any idea on how to address it?


If the reference from DBI::fetchrow_arrayref is coming back read-only, attempting to overwrite it won't help: the reference is read-only, not the thingie (i.e., the array with column values).

Make your own copy right at the source if you need destructive updates, e.g.,

my $arg_ref = [ $sth->fetchrow_array ];


Readonly and readonly are different. (Notice the capital R and lowercase r. ;-) )

See the Scalar::Util documentation for why this is true:

readonly SCALAR

Returns true if SCALAR is readonly.

sub foo { readonly($_[0]) }
$readonly = foo($bar);              # false
$readonly = foo(0);                 # true

This is more about aliases (such as those passed in via foreach loops or in @_, and not the Readonly module.


I think I have it figured out. Robert P was right, but he only got half of the answer: Readonly and readonly do different things though they should do the same thing, the fact that they don't is a bug. I'll try to explain what is going on.

Readonly has two implementations for scalars: one (Readonly::XS) that is based on the SvREADONLY flag and one (Readonly::Scalar) based on ties that emulates the SvREADONLY flag.

readonly also has two implementations, one in Perl (which does self assignment and checks if it throws an exception or not), and one in XS (again based on the SvREADONLY flag).

There are 4 possible combinations, and unfortunately the one that is most common (pure perl Readonly and XS readonly) is the only one that doesn't work as advertised.

Here's the crux: sub Readonly::Readonly actually doesn't use Readonly::XS at all, only sub Readonly::Scalar does. This is probably a bug. readonly correctly reports that the variable is not a readonly variable: its readonlyness is faked by a tie.

It's Readonly that's at fault here IMO, it should do the right thing when it can and document when it can't. Right now it's doing neither of those.


It doesn't look like the result of Scalar::Util::readonly can be trusted used how you want to use it. Witness:

perl -MScalar::Util=readonly -MReadonly -wle'
    Readonly my $arg_ref => [ qw(a b c)];
    print readonly $arg_ref;
    $arg_ref = 1;'

prints:

0
 Modification of a read-only value attempted at -e line 1.

(Tested under perl5.8.8 with Readonly 1.03, Scalar::Util 1.23)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜