in reply to typeglob reference deletes global lexical

It seems I need to explain more about the "why" of what I'm doing. Here's an example:
sub initialize { return shift->call_super_before(\@_, sub { my($self) = @_; $self->die($self->get('values'), undef, 'number of elements mu +st be even') unless @{$self->get('values')} % 2 == 0; return; }); }

call_super_before uses code_ref_for_subroutine to figure out what the SUPER is from a $proto/$self and caller. I want SUPER to do something (put "values" on $self) and then I'm going to check the result. With call_super_before I don't need to know what SUPER returns or what it takes, it's all transparent to the subclass.

One suggestion was to use ->can, but this doesn't work, because it will return the subclass's method, not SUPER's method.

As to "what global lexicals" disappear, it's all of them as near as I can tell. A global lexical is one which is declared in the package scope so properly "package lexicals disappear". The difficulty is that the lexicals are undefined after they are initialized, that is,

my($_BAR) = 1; sub foo { return shift->call_super_before(\@_, sub { die('gone') unless $_BAR; return; }); }

During the first call to foo, $_BAR is false, even though it was initialized to 1.

Here's another tidbit, which is probably related:

package T1; sub s1 {print("T1:s1\n")} package T2; use base T1; package T3; use base T2; sub s1 {shift->SUPER::s1} package main; no strict 'refs'; exists($T2::{s1}) && die('not here'); T3->s1; exists($T2::{s1}) && die('here');

During the search for SUPER methods, $T2::{s1} is created with an empty value for *{$T2::{s1}}{CODE}. It's there, but not there. This is what I mean by semi-autovivification: the typeglob is created, but it doesn't contain anything.

Rob

Replies are listed 'Best First'.
Re^2: typeglob reference deletes global lexical
by ikegami (Patriarch) on Nov 08, 2008 at 01:34 UTC

    During the first call to foo, $_BAR is false, even though it was initialized to 1.

    Assuming the value didn't change, that usually means that foo was called before the assignment occurred.

    use strict; use warnings; my $x = 1; sub foo { print("[$x]\n"); } BEGIN { foo(); } # Prints "[]" and gives an undefined warning.

    Or since you're doing symtab manipulations, maybe it's getting clobbered by something. But that would mean the variable isn't a lexical (my) variable as you claim it is.

    Seeing you didn't provide code that reproduces the problem, there's not much we can do.

      The code is here http://www.bivio.biz/hm/download-bOP I can't seem to distill it to the point of reproducing the problem in a short script.

      Needless to say a simple implementation does not produce the bug. I've stripped all the non-essential parts out, and started mod_perl, but the failure does show up. It is reliable for a particular package and code configuration. However, changing code in other packages can cause the failure to disappear.

        mod_perl? Don't use "global" lexicals in mod_perl Registry script. Had you turned on warnings, you would have gotten one. mod_perl wraps your script in a function, so you basically get
        sub mod_perl_wrapper { ##### Begining of script ##### use strict; use warnings; my $global = $_[0]; # Say some value from the request. sub foo { # Warms 'Variable "$global" will not stay shared' print("$global\n"); } foo(); ##### End of script ##### } mod_perl_wrapper(4); # First request prints "4" mod_perl_wrapper(5); # Subsequent requests also prints "4"

        Use a package variable instead.

        sub mod_perl_wrapper { ##### Begining of script ##### use strict; use warnings; local our $global = $_[0]; # Say some value from the request. sub foo { print("$global\n"); } foo(); ##### End of script ##### } mod_perl_wrapper(4); # 1st request prints "4" mod_perl_wrapper(5); # 2nd request prints "5"

        I almost mentioned this earlier. I can't believe you went through all this trouble rather than turning on warnings. Even if you don't normally use them for whatever reason, adding use strict; and use warnings; is the first thing you should do when you have a problem you can't explain.

Re^2: typeglob reference deletes global lexical (SUPER:: cache)
by ikegami (Patriarch) on Nov 08, 2008 at 01:48 UTC

    the typeglob is created, but it doesn't contain anything.

    It's not empty. It caches the SUPER(T2::s1)T1::s1 relation.

    { package T1; sub s1 { } } { package T2; use base T1; } { package T3; use base T2; sub s1 { shift->SUPER::s1 } } use Devel::Peek qw( Dump ); { warn("T1::s1: ", \&T1::s1, "\n"); warn("T2::s1 (pre):\n"); Dump(*T2::s1); T3->s1; warn("T2::s1 (post):\n"); Dump(*T2::s1); }
    >perl script.pl 2>&1 | findstr ": CODE CV" T1::s1: CODE(0x183180c) T2::s1 (pre): CV = 0x0 CVGEN = 0x0 T2::s1 (post): CV = 0x183180c CVGEN = 0x91

    SUPER doesn't need to be explicitly mentioned.

    { package T1; sub s1 { } } { package T2; use base T1; } use Devel::Peek qw( Dump ); { warn("T1::s1: ", \&T1::s1, "\n"); warn("T2::s1 (pre):\n"); Dump(*T2::s1); T2->s1; warn("T2::s1 (post):\n"); Dump(*T2::s1); }
    >perl script.pl 2>&1 | findstr ": CODE CV" T1::s1: CODE(0x183180c) T2::s1 (pre): CV = 0x0 CVGEN = 0x0 T2::s1 (post): CV = 0x183180c CVGEN = 0x8e

      I've been trying to narrow this down, and it does get pretty weird. I've got it to the point of calling a closure causes the failure, and if the file lexical is read before the closure call, it doesn't disappear.

      Since I can't reproduce it outside mod_perl (1.x, btw), I suspect this has little to do with typeglobs so sorry for the confusing subject.

      I've got my workaround so I'm going to call it quits on reducing the code to a reproducible failure.

      Rob
Re^2: typeglob reference deletes global lexical
by JavaFan (Canon) on Nov 08, 2008 at 00:39 UTC
    A global lexical is one which is declared in the package scope so properly "package lexicals disappear".
    You got your terminology mixed up. A lexical is by definition lexically scoped. It exists inside a block, and not outside that block (there's a block at the file level as well).

    And package variable, that is, a variable with a package wide scope, is not a lexical variable.

    As for your last tidbit, you don't say what it does for you, and what you expect it to do, but when I run it, it prints "T1:s1", which is what I expect.