Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Re: UPDATED, mostly solved: separation of define + assignment different from combination?

by andal (Hermit)
on Feb 12, 2014 at 08:48 UTC ( [id://1074599]=note: print w/replies, xml ) Need Help??


in reply to UPDATED, mostly solved: separation of define + assignment different from combination?

Uph. It took me a while to understand what you are trying to say :)

I guess, this might be considered a bug. Here's the example of code to reproduce it.

use warnings; sub FUNC{ print "I'm in func\n"; } { local(*FUNC) = sub { print "now overridden\n"; }; FUNC(); } FUNC();
The code above works correctly, but still produces warning. Somehow, warnings generator does not see that "local" shall save away old function reference and no redefining happens because after "local" function FUNC "does not exist" anymore.

  • Comment on Re: UPDATED, mostly solved: separation of define + assignment different from combination?
  • Download Code

Replies are listed 'Best First'.
Re^2: UPDATED, mostly solved: separation of define + assignment different from combination?
by Anonymous Monk on Feb 12, 2014 at 08:56 UTC
    There is no bug, everything is working as it should, warnings is doing its job
    use warnings; sub FUNC{ print "I'm in func\n"; } { local(*FUNC) = sub { print "now overridden\n"; }; FUNC(); ## THIS IS LINE 6 } FUNC(); __END__ Subroutine main::FUNC redefined at - line 6. now overridden I'm in func
      Especially the comment "THIS IS LINE 6" on line 7 is nice.
      لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
        probably meant "# WILL EXECUTE LINE SIX"
      There is no bug, everything is working as it should, warnings is doing its job

      Well, first of all you made mistake, the line 6 is where the assignment is done. Second, if you separate the assignment from localizing, then no warning is produced. According to documentation, there should be no difference. Whether one writes

      local(*FUNC) = sub {};
      or
      local(*FUNC); *FUNC = sub {};
      things should be the same. But they are not. First one produces warning, second one - not. That is why I said, that it might be considered a bug.

        Well, first of all you made mistake, the line 6 is where the assignment is done.

        :)

        Second, if you separate the assignment from localizing, then no warning is produced.

        um, put that in the code?

        use warnings; sub RO { warn "RO" } sub SHAM { warn "SHAM" } RO(); { local *RO = sub { warn "BO" }; RO(); } SHAM(); { local *SHAM; *SHAM = sub { warn "BO" }; SHAM(); } RO(); SHAM(); __END__ RO at - line 2. Subroutine main::RO redefined at - line 5. BO at - line 5. SHAM at - line 3. BO at - line 7. RO at - line 2. SHAM at - line 3.

        So, that kinda makes sense to me, when its redefined, you get warning

        When its undefined, then its defined , you get no warning

        So , to see if its a bug , I look at what warnings says which is

        Subroutine %s redefined (W redefine) You redefined a subroutine. To suppress this warning, say { no warnings 'redefine'; eval "sub name { ... }"; }

        So my new code snippet is

        $ perl -le " use warnings; sub foo { warn 1 } foo(); local *foo; sub f +oo { warn 2 } foo(); " Subroutine foo redefined at -e line 1. 2 at -e line 1. Undefined subroutine &main::foo called at -e line 1.

        Hmm, at compile time its redefined, but at run time its undefined

        Oh right, eval

        $ perl -le " use warnings; sub foo { warn 1 } foo(); local *foo; eval +q{sub foo { warn 2 }}; foo(); " 1 at -e line 1. 2 at (eval 5) line 1.

        no redefined warning is given

        And third take round trip

        $ perl -le " use warnings; sub foo { warn 1 } foo(); { local *foo; eva +l q{sub foo { warn 2 }}; foo(); } foo(); " 1 at -e line 1. 2 at (eval 5) line 1. 1 at -e line 1.

        no redefined warning is given

        So , yup, the situation makes sense from a technical point, at the time the new sub is defined, the old sub doesn't exist in the current scope -- current stash -- it doesn't exist

        Could perl/warnings be made to detect this case? Sure

        Would it be worth it? I doubt it -- its essentially double checking

        So, I don't see it as a bug or undesireable; I don't see a compelling reason to change it

        Cheers

      The above doesn't really reproduce the error as 'FUNC' was in a 'sub' that got called recursively (which triggered the warning).

      Also, in that example, it is hard to see when the warning was 'issued', as STDERR is not buffered while STDOUT is, so the warning(on STDERR) would be seen (in this case), before any output from STDOUT (flushed @ program exit).

      I've rewritten the code below multiple times to experiment w/outcome. This reproduces the problem, and shows when an object containing the 'local' gets destroyed. There are two counters printed -- a "singleton" counter (1 for package), and a local copy of the global when the object was created (cuz they aren't the same on destruction). Hope this doesn't give anyone a headache like it did me in writing it...;-) Minor change w/change-line to allow breaking define+assign (i.e. via the '#' in column 2 (before the code) -- removing or not gets non-split vs. split define+assign

      #!/usr/bin/perl use warnings; use strict; use P; { package pkg; use warnings; use strict; use P; use Types::Core; our $cnt=0; sub new { my $p = shift; my $c = ref $p || $p; Pe "pkg %s created", ++$cnt; $p = bless { cnt => $cnt, fnc => sub { my $p2 = ref $_[0] ? shift : __PACKAGE__; Pe "fnc %d calling %s", $cnt, $p2->FUNC; undef; } }, $c; } sub destroy { Pe "pkg %s(%s) destroyed", $cnt, EhV $_[0], cnt; undef + } sub DESTROY { goto &destroy } } package main; sub callfunc(;$$); #silence warn about proto not ready sub callfunc (;$$) { my $p = pkg->new; my ($callfunc, $recur) = @_; $callfunc||=0; $recur||=0; local * FUNC #; *FUNC # change line = sub () { Pe "In FUNC, cnt=%s", $p->{cnt}; undef }; FUNC() if $callfunc; callfunc($callfunc, $recur) if $recur && $recur--; } Pe "** no recursion"; callfunc; callfunc 1; Pe "** split define/assign recursion"; callfunc 0,1; callfunc 1,1; pkg::destroy
      ---output for non-split:---
      ** no recursion pkg 1 created pkg 1(1) destroyed pkg 2 created In FUNC, cnt=2 pkg 2(2) destroyed ** split define/assign recursion pkg 3 created pkg 4 created Subroutine main::FUNC redefined at /tmp/tst2.pl line 29. pkg 4(4) destroyed pkg 4(3) destroyed pkg 5 created In FUNC, cnt=5 pkg 6 created Subroutine main::FUNC redefined at /tmp/tst2.pl line 29. In FUNC, cnt=6 pkg 6(6) destroyed pkg 6(5) destroyed pkg 6(∄) destroyed
      ---output for split case ---
      ** no recursion pkg 1 created pkg 1(1) destroyed pkg 2 created In FUNC, cnt=2 pkg 2(2) destroyed ** split define/assign recursion pkg 3 created pkg 4 created pkg 4(4) destroyed pkg 4(3) destroyed pkg 5 created In FUNC, cnt=5 pkg 6 created In FUNC, cnt=6 pkg 6(6) destroyed pkg 6(5) destroyed pkg 6(∄) destroyed
      I used Types::Core's EhV, to allow dereferencing $_[0] and returning the value of $_[0] in 1 step. I used P's 'Pe' instead of 'P' to print to STDERR so my output would be unbuffered and intermixed with perl's STDERR stream.

      Side note: In case your local font doesn't display the default 'undef' sign used by P, (present in parens on the last line of output), it looks like 'E' with a diagonal crossout through it, but backward (in case your font doesn't display it).

      As the output shows above, the warning message only occurs on recursive calls to the sub where the local defines the sub (and breaking the local into a separate declaration followed by the assignment doesn't show the problem....ah crud.. didn't put that in the example -- **UPDATED**

      Now we can see that the recursive value gets destroyed before returning so no overwrite is detected...

      p.s. I note the <code> function is broken -- it doesn't post output "as is", but turns it into non-standard, decimal HTML (i.e. &&;#8708 is a decimal number, and current standards default to hex as in "&&;#x2204;" ).

      p.p.s. -- I note that while the <code> doesn't maintain literal values in displaying code, these comments do, so if your charset has the character it should be between the quotes: "∄". Cheers!

        ... use P; use Types::Core; ...

        Sorry , but tThat is not a minimal demonstration of a bug in perl, something you should have included in the OP

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1074599]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (5)
As of 2024-04-18 18:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found