24

I have some auto-generated code which effectively writes out the following in a bunch of different places in some code:

no warnings 'uninitialized';
local %ENV = %ENV;
local $/   = $/;
local @INC = @INC;
local %INC = %INC;
local $_   = $_;
local $|   = $|;
local %SIG = %SIG;
use warnings 'uninitialized';

When auto-generating code, some argue that it's not strictly necessary that the code be "beautiful", but I'd like to pull that out into a subroutine. However, that would localize those variables in that subroutine. Is there a way to localize those variables in the calling stack frame?

Update: In a similar vein, it would be nice to be able to run eval in a higher stack frame. I think Python already has this. It would be nice if Perl did, too.

brian d foy
  • 129,424
  • 31
  • 207
  • 592
Ovid
  • 11,580
  • 9
  • 46
  • 76
  • Are you sure you saw this in Python? Tcl's `uplevel` comes into mind. But hexten's answer is much better anyway.. – cfi Jan 11 '12 at 14:20

6 Answers6

30

Perhaps you can arrange for the code that uses those locals to be generated as a closure? Then you could

sub run_with_env {
    my ($sub, @args) = @_;
    no warnings 'uninitialized';
    local %ENV = %ENV;
    local $/   = $/;
    local @INC = @INC;
    local %INC = %INC;
    local $_   = $_;
    local $|   = $|;
    local %SIG = %SIG;
    use warnings 'uninitialized';  
    $sub->(@args);
}

run_with_env(sub {
    # do stuff here
});

run_with_env(sub {
    # do different stuff here
});
hexten
  • 1,169
  • 7
  • 10
6

Not sure why QuantumPete is being downvoted, he seems to be right on this one. You can't tell local to initialize variables in the calling block. Its functionality is special, and the initialization/teardown that it does only works on the block where it was run.

There are some experimental modules such as Sub::Uplevel and Devel::RunBlock which allow you to attempt to "fool" caller() for subroutines or do a 'long jump return' of values to higher stack frames (respectively), but neither of these do anything to affect how local treats variables (I tried. :)

So for now, it does indeed look like you will have to live with the local declarations in the scope where you need them.

Adam Bellaire
  • 108,003
  • 19
  • 148
  • 163
3

I'm not terribly familiar with Perl, so forgive me if it is actually possible. But normally, variables local to a stack frame are only available within that stack frame. You can't access them from either a higher or lower one (unless you do some hacky pointer arithmetic but that's never guaranteed to succeed). Large blocks of variable declarations are unfortunately something you will have to live with.

QuantumPete

Peter Kühne
  • 3,224
  • 1
  • 20
  • 24
  • 1
    These variables are built-in global variables. They don't have the usual cognitive overhead of globals as they're well-known and defined. Unfortunately, they still have global effect (as global variables do) and the localization restricts changes to the current scope. – Ovid Oct 14 '08 at 10:11
  • 2
    In addition, local doesn't have the behavior you're thinking of, not exactly. local lets you access the variable that's localized from then on, modify it, update it, change it, and let it continue in that calling stack as your new/modified value until it leaves the closure it was localized in. – Robert P Oct 16 '08 at 20:06
3

perldoc perlguts says:

   The "Alias" module implements localization of the basic types within
   the caller's scope.  People who are interested in how to localize
   things in the containing scope should take a look there too.

FWIW. I haven't looked at Alias.pm closely enough to see how easy this might be.

1

In TCL you can use uplevel. As for Perl, I don't know.

brian d foy
  • 129,424
  • 31
  • 207
  • 592
Hugh Allen
  • 6,509
  • 1
  • 34
  • 44
  • 3
    I have to wonder why the hell there's a Wikipedia entry for a TCL keyword? Should I add one for unpack now? :) – Ovid Oct 14 '08 at 12:18
  • Something like [Sub::Uplevel](http://search.cpan.org/perldoc?Sub::Uplevel)? Is that what it's for? – bart Oct 14 '08 at 15:10
  • I don't think Sub::Uplevel helps at all I'm afraid - "caller" isn't a namespace. – Hugh Allen Oct 14 '08 at 15:19
0

Perl has Sub::Uplevel

Brad Gilbert
  • 33,846
  • 11
  • 78
  • 129
JDrago
  • 2,079
  • 14
  • 15