Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I would like to be able to reattach an anonymous sub to its package.
#!/usr/bin/perl use warnings; use strict; use Data::Dumper; $Data::Dumper::Deparse = 1; package p1; our $x = 1; my $func = sub { print $x,"\n" }; $func->(); package p2; our $x = 100; $func->();
Is there a "good" way to do this? (Not involving deparse?)

Replies are listed 'Best First'.
Re: anonymous sub, packages, global variables
by LanX (Saint) on May 17, 2011 at 18:25 UTC
    you have to assign the coderef to the new glob.

    For simplicity the following code is a cut&paste from my scratchpad, (had to help KennethK in the CB to figure it out)

    use strict; use warnings; $\="\n"; *tst=sub { print "orig" }; tst(); my $safe=\&tst; { no warnings; *tst=sub { print "new"}; } tst(); { no warnings; *tst=$safe; } tst();

    it shows how to safe, replace and reestablish a function.

    If you use local *tst=sub {...} you can also restrict the new function till the end of scope.

    Cheers Rolf

Re: anonymous sub, packages, global variables
by ikegami (Patriarch) on May 17, 2011 at 18:27 UTC

    What do you mean by "reattach"? If you want to make it so it can be called as func(), you can use

    *func = $func;
Re: anonymous sub, packages, global variables
by wind (Priest) on May 17, 2011 at 18:38 UTC

    You can attach it to either a sub reference, or as a scalar to a sub reference

    *p2::func = $func; package p2; our $x = 100; func();
    or
    *p2::func = \$func; package p2; our $x = 100; $func->();

    However, both of those will still use the '$x' global defined in package 'p1'. To fix that, rely on parameters instead of a global var.

    #!/usr/bin/perl use warnings; use strict; package p1; our $x = 1; my $func = sub { print $_[0],"\n" }; $func->($x); *p2::func = $func; package p2; our $x = 100; func($x);

    Or use caller to determine where the function was called from (very messy).

    #!/usr/bin/perl use warnings; use strict; package p1; our $x = 1; my $func = sub { my $pkg = (caller)[0]; no strict 'refs'; print ${"${pkg}::x"},"\n" }; $func->(); *p2::func = $func; package p2; our $x = 100; func();
      *p2::func = \$func;

      sorry but thats nonsense, your assigning a coderef to the scalar slot of the glob, not to the code slot!

      update:

      DB<101> $coderef=sub {print "nonsense"} DB<102> *glob=\$coderef DB<103> &$glob nonsense DB<104> glob()

      Cheers Rolf

        Exactly, because he wanted to be able to call his function using $func->() in package p2 just like in p1. I therefore showed how how to achieve both potentially desired results: being able to call his function like func() or by $func->() like he had in his code.

        I wouldn't advocate either methods, but it's what he asked for.