Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

runtime problem; elusive error

by perl-diddler (Chaplain)
on Sep 20, 2007 at 11:29 UTC ( [id://640089]=perlquestion: print w/replies, xml ) Need Help??

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

Replies are listed 'Best First'.
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

      ooh, nice one.

      I shall bookmark this thread, so that I can point it out to people who have drunk the PBP Kool-aid™ and tout Readonly as the best thing since sliced bread (or at least better than constant). May they see the error of their ways :)

      • another intruder with the mooring in the heart of the Perl

      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).

        though I sure don't know why it's returning "=28"

        That's the bitwise string-OR of the stringified decimal representations of the three values, i.e.

        "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'

        I'd like to be able to put a "numeric" or "string" in front a var to let it know what I want

        You can. They are spelled "0+" and "''." respectively.

        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
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.

      my crude solution is to use string eval ...

      What also seems to work is

      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).

        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

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...

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
      Doesn't look like installing Readonly::XS helps:
      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
      --
      Andreas
        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

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://640089]
Approved by almut
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (3)
As of 2024-03-29 06:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found