use warnings; use strict; sub a { "unchanged" }; sub print_a { print a(), "\n" }; #### no strict 'refs'; no warnings 'redefine'; { local *a = sub { "changed" }; print_a(); # prints "changed" } #### print_a(); # prints "unchanged" #### sub localize_a_and_call_fn(&@) { my ($fn, @args) = @_; local *a = sub { "changed" }; $fn->(@args); } #### localize_a_and_call_fn( \&print_a ); # prints "changed" localize_a_and_call_fn { print "a() => ", a(), "\n"; }; # prints "a() => changed" #### sub localize_and_call_fn { my ($locals, $fn, @args) = @_; local *$_ = sub { "changed" } for @$locals; $fn->(@args); } #### localize_and_call_fn( [qw(a b c)], \&print_a ); # prints "unchanged" #### # for (@$locals) { # local *$_ = sub { "changed" }; # } #### sub localize_and_call_fn_2 { my ($locals, $fn, @args) = @_; for my $sym (@$locals) { my $f = $fn; $fn = sub { local *$sym = sub { "changed" }; $f->(@_); } } $fn->(@args); } localize_and_call_fn_2( [qw(a b c)], \&print_a ); # prints "changed" #### # (sub { # local *c = sub { "changed" }; # (sub { # local *b = sub { "changed" }; # (sub { # local *a = sub { "changed" }; # (\&print_a)->(@_); # })->(@_) # })->(@_) # })->();