perl-diddler has asked for the wisdom of the Perl Monks concerning the following question:
I have a section of code extracted from a larger prog with this problem. Tried to pare it down as much as possible. The code is this:
!/bin/perl -w
use strict;
use Readonly;
Readonly my $DBG_ANY => -1;
Readonly my $DBG_INFO => 0x0004;
Readonly my $DBG_KEYS => 0x0008;
Readonly my $DBG_RAND => 0x0080;
my @Vals = ( $DBG_ANY, 1, 2,
# $DBG_INFO, $DBG_KEYS,
);
Readonly my $_debug_ops => ($DBG_RAND | $DBG_KEYS | $DBG_INFO);
printf "debugops = 0x%04x\n",$_debug_ops;
When I run it, I get:
Argument "=28" isn't numeric in printf at ./dbgtst line 16.
debugops = 0x0000
If I uncomment the line with "$DBG_INFO, $DBG_KEYS", the program runs as I'd expect and gives output:
debugops = 0x008c
If I put the init of _debug_ops before the "@Vals", then I always get the error from above (i.e. - whether comment is there or not).
I have to be missing something incredibly obvious and just can't see the trees for the forest.
Can anyone see why the above is not working or is something broken in perl (seems too simple to be that).
I'm running 5.8.8 and it fails the same way on both linux and under cygwin.
A cluestick would be appreciated...:-)
TIA...
Linda
Re: runtime problem; elusive error
by GrandFather (Saint) on Sep 20, 2007 at 12:14 UTC
|
A small clue: the nastiness is in, or is related to Readonly. If you can do without the read only stuff the code works as expected. If you instead:
use strict;
use warnings;
use constant DBG_ANY => -1;
use constant DBG_INFO => 0x0004;
use constant DBG_KEYS => 0x0008;
use constant DBG_RAND => 0x0080;
my @Vals = ( DBG_ANY, 1, 2, DBG_INFO, DBG_KEYS, );
my $_debug_ops = (DBG_RAND | DBG_KEYS | DBG_INFO);
printf "debugops = 0x%04x\n",$_debug_ops;
it prints:
debugops = 0x008c
Perl is environmentally friendly - it saves trees
| [reply] [d/l] [select] |
|
| [reply] |
|
Looks like the "workaround" would be (removing the @Vals) line, as that hides
the errormy $_debug_ops = (0 | DBG_RAND | DBG_KEYS |DBG_INFO);
That puts in numeric context...sigh. Sometimes I'd like to be able to put a "numeric" or "string" in front a var to let it know what I want. The alternative is use something of the appropriate type (num or string), first, but that's not nearly so clear as being able to put in a "numeric" , like one does with "scalar", now.
Thanks for the heads up...I'd report it as a but, but not sure how they'd fix it -- though I sure don't know why it's returning "=28" (hex equiv to left paren).
It's interesting that the XS version is consistent (i.e. same constant).
| [reply] [d/l] |
|
"128" | "8" | "4"
or, more eplicitly
chr(ord('1') | ord('8') | ord('4')) . # '='
chr(ord('2') | ord('') | ord('') ) . # '2'
chr(ord('8') | ord('') | ord('') ) # '8'
| [reply] [d/l] [select] |
|
my $x = '8';
my $y = '16';
print((0+$x) | (0+$y), "\n"); # 24
print((''.$x) | (''.$y), "\n"); # 96
Update: Oops, that doesn't quite answer your question. If the variable wasn't read-only, you could do the following:
$x .= ''; # Stringify
$x += 0; # Numerify
| [reply] [d/l] [select] |
Re: runtime problem; elusive error
by kyle (Abbot) on Sep 20, 2007 at 12:29 UTC
|
I discovered also GrandFather's note that Readonly is somehow the source of misery. What I see happening is that the values set with Readonly are set as strings rather than numbers. According to perlop, the bitwise OR operating on strings is different than if it sees integers.
What's very strange, though, is that the numbers-as-strings thing only happens after they've been used once. That's why your usage of them in @Vals is triggering the bug. If I leave your piece commented out but print them with Data::Dumper, I get the same behavior (but not with a simple print—weird!).
Anyway, my crude solution is to use string eval to get closer to what you want.
Readonly my $_debug_ops => eval "($DBG_RAND | $DBG_KEYS | $DBG_INFO)";
That works in this case, but it's not very satisfying in general. I don't really understand what's going on in Readonly, so I haven't been able to come up with something better. | [reply] [d/l] [select] |
|
Readonly my $_debug_ops => $DBG_RAND+0 | $DBG_KEYS+0 | $DBG_INFO+0;
but I'm not sure if it's the "+0 = force numeric" aspect or the
associated pre-evaluation of the variables that's making this work... (of course, this workaround isn't very satisfying either).
Anyhow, it's probably best to just stay away from using Readonly...
(I had also already been bitten by other subtle weirdnesses).
| [reply] [d/l] |
|
Slightly cleaner (though admittedly, it doesn't quite "hit the spot" for satisfaction) is just or'ing with 0 as the first thing: "$debug_ops = 0 | $DBG_RAND | $DBG_KEYS | $DBG_INFO; That does the same thing (I think) as your +0 in this situation. Not sure how it gets the other value...weird!
Thanks!
Linda
| [reply] |
Re: runtime problem; elusive error
by almut (Canon) on Sep 20, 2007 at 14:22 UTC
|
It seems the tiedscalar magic is somehow being applied incorrectly,
when a 'virgin' readonly scalar is being used in a bitwise OR operation.
With 'virgin' I mean that the variable hasn't been accessed before.
Once the variable has been accessed/initialised (note the difference in
the Devel::Peek dump before and after), things start to work as expected,
i.e. the OR operation then seems to default to numeric interpretation.
Compare:
use Devel::Peek;
use Readonly;
Readonly my $C1 => 0x0004;
Readonly my $C2 => 0x0008;
Dump($C1); # before first evaluation
#Dump($C2);
my @x = ($C1, $C2); # somehow access variables
my $C3 = $C1 | $C2;
Dump($C1); # after first evaluation
#Dump($C2);
print "\nValue of C3 = ", $C3, "\n";
If you comment out the line "my @x = ($C1, $C2);", $C3 will
be "<" (i.e. string OR of "8" | "4"), while with the line being active,
you'd get 12 (i.e. numeric OR of 8 | 4 ).
Example output without pre-evaluating $C1 and $C2:
SV = PVMG(0x69b788) at 0x65eb00
REFCNT = 1
FLAGS = (PADBUSY,PADMY,GMG,SMG,RMG)
IV = 0
NV = 0
PV = 0
MAGIC = 0x6e8ff0
MG_VIRTUAL = &PL_vtbl_packelem
MG_TYPE = PERL_MAGIC_tiedscalar(q)
MG_FLAGS = 0x02
REFCOUNTED
MG_OBJ = 0x63c430
SV = RV(0x676bd8) at 0x63c430
REFCNT = 1
FLAGS = (ROK)
RV = 0x6b87d0
SV = PVMG(0x69b750) at 0x6b87d0
REFCNT = 1
FLAGS = (PADBUSY,PADMY,OBJECT,IOK,POK,pIOK,pPOK)
IV = 4
NV = 0
PV = 0x7083b0 "4"\0
CUR = 1
LEN = 8
STASH = 0x6b8990 "Readonly::Scalar"
SV = PVMG(0x69b788) at 0x65eb00
REFCNT = 1
FLAGS = (PADBUSY,PADMY,GMG,SMG,RMG,pIOK,pPOK) # <---
IV = 4
NV = 0
PV = 0x6b4c50 "4"\0
CUR = 1
LEN = 8
MAGIC = 0x6e8ff0
MG_VIRTUAL = &PL_vtbl_packelem
MG_TYPE = PERL_MAGIC_tiedscalar(q)
MG_FLAGS = 0x02
REFCOUNTED
MG_OBJ = 0x63c430
SV = RV(0x676bd8) at 0x63c430
REFCNT = 1
FLAGS = (ROK)
RV = 0x6b87d0
SV = PVMG(0x69b750) at 0x6b87d0
REFCNT = 1
FLAGS = (PADBUSY,PADMY,OBJECT,IOK,POK,pIOK,pPOK)
IV = 4
NV = 0
PV = 0x7083b0 "4"\0
CUR = 1
LEN = 8
STASH = 0x6b8990 "Readonly::Scalar"
Value of C3 = <
Strange... | [reply] [d/l] [select] |
Re: runtime problem; elusive error
by syphilis (Archbishop) on Sep 20, 2007 at 12:36 UTC
|
The bug may disappear if you install Readonly::XS ... not sure - just a thought.
Readonly::XS provides about the simplest way there is of making scalars readonly. (Note that you don't explicitly "use Readonly::XS;". You just install it and Readonly will automatically use it for making scalars readonly.)
Cheers, Rob | [reply] |
|
use warnings;
use strict;
use Readonly;
use Readonly::XS;
Readonly my $DBG_INFO => 0x0004;
Readonly my $DBG_KEYS => 0x0008;
Readonly my $DBG_RAND => 0x0080;
Readonly my $_debug_ops => ($DBG_RAND | $DBG_KEYS | $DBG_INFO);
printf ("%04x\n", $_debug_ops);
printf ("%04x\n", $DBG_RAND | $DBG_KEYS | $DBG_INFO);
__END__
$ perl -wl 640089.pl
Argument "=28" isn't numeric in printf at 640089.pl line 12.
0000
008c
Readonly is up to date (1.03).
Readonly::XS is up to date (1.04).
perl, v5.8.5
linux 2.6.9
| [reply] [d/l] |
|
Doesn't look like installing Readonly::XS helps
Then I guess just Inline::C it:
use warnings;
use strict;
use Inline C => <<'EOC';
void ro_on(SV * x) {
SvREADONLY_on(x);
}
EOC
my ($DBG_ANY, $DBG_INFO, $DBG_KEYS, $DBG_RAND)
= (-1, 0x0004, 0x0008, 0x0080);
ro_on($_) for($DBG_ANY, $DBG_INFO, $DBG_KEYS, $DBG_RAND);
my $_debug_ops = $DBG_RAND | $DBG_KEYS | $DBG_INFO;
ro_on($_debug_ops);
printf "debugops = 0x%04x\n",$_debug_ops;
Cheers, Rob | [reply] [d/l] |
|
|