Different results while evaluating Readonly variable

I noticed that with variables declared with the Readonly module, evaluating a variable several times can give different results.

 >perl -Mbigint -MReadonly -wE "Readonly my $V => 1; foreach (1..2) { say 0 + '1000000000000001' * $V }; 1000000000000000 1000000000000001 

Why? It looks like the first time the variable is interpreted in a string, the second time in a numerical context. I assume that if it is numerical, the Math::BigInteger module will overload the '*' operator, giving an accurate result. This is a bug in the Readonly module, and is there a way to avoid this?

I am using perl 5.10 and Readonly 1.03 without Readonly::XS .

I can reproduce this with

  • v5.10.0 on MSWin32-x86-multi-thread (ActivePerl)
  • v5.10.0 on linux x86_64-linux-thread-multi .
  • v5.12.0 on Windows (ActivePerl)

I do not meet with v5.14.2 (ActivePerl).

I also played it using Readonly 1.04. I'm not quite sure if this is related, but Scalar::Util::looks_like_number behaves similarly:

 >perl -MReadonly -MScalar::Util -Mbigint -wE "say $Readonly::VERSION; Readonly my $V => 1; foreach (1..2) { say Scalar::Util::looks_like_number $V; }" 1.04 0 1 
+7
perl operator-overloading biginteger readonly tie
source share
1 answer

This seems to be an overload error when using tie d variables, which were fixed in later versions of perl. The following sample program shows the difference:

 use strict; use warnings; use 5.010; sub TIESCALAR { bless {}, 'main'; } sub FETCH { say 'FETCH'; shift; } use overload '+' => sub { say 'add called'; }, '0+' => sub { say 'tonum called'; }; tie my $a, 'main'; my $b = bless {}, 'main'; say "adding non-tied (call $_): ", $b+1 for (1..2); say "adding tied (call $_): ", $a+1 for (1..2); 

Exit with Perl v5.10.0 :

 add called adding non-tied (call 1): 1 add called adding non-tied (call 2): 1 FETCH tonum called adding tied (call 1): 2 add called adding tied (call 2): 1 

Perl tries to convert the numeric value 0+ before the overloaded + operator on the first evaluation of the bound variable, which leads to standard perl arithmetic. In perl> = 5.14, the output looks as expected:

 add called adding non-tied (call 1): 1 add called adding non-tied (call 2): 1 FETCH add called adding tied (call 1): 1 FETCH add called adding tied (call 2): 1 

From perldoc overload :

 BUGS .... Before Perl 5.14, the relation between overloading and tie()ing was broken. Overloading was triggered or not based on the previous class of the tie()d variable. This happened because the presence of overloading was checked too early, before any tie()d access was attempted. If the class of the value FETCH()ed from the tied variable does not change, a simple workaround for code that is to run on older Perl versions is to access the value (via "() = $foo" or some such) immediately after tie()ing, so that after this call the previous class coincides with the current one. 
+2
source share

All Articles