Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

local keyword does not work with references

Tags:

perl

The following code prints <oof foo zab><foo foo baz>:

use v5.36;
use warnings;

our $foo = 'foo';
our %bar = (
  foo => \$foo,
  baz => 'baz',
);

{
  local ($foo, %bar) = ($foo, %bar);
  ($foo, $bar{baz}) = qw(oof zab);
  print "<$foo ${$bar{foo}} $bar{baz}>";
}

print "<$foo ${$bar{foo}} $bar{baz}>";

Is there a way to make it print <oof oof zab><foo foo baz> without copy/pasting %bars definition into the inner scope?

EDIT:

I realize that I have phrased my question poorly.

The outer scope represents some given code with many such $foos and %bars as well as functions which behave according to those variables.

The inner scope represents tests for the outer scope, where I wanted to localize variables, modify them and test how the functions behave. Each test was supposed to start with the initial conditions, thus the local. It is not feasible to duplicate the many variable assignments into the inner scope, because that might become outdated quickly.

My question might look like an xy-problem, but I had hoped that locals current behaviour is a perl bug.

like image 315
Damian Avatar asked Dec 29 '25 07:12

Damian


2 Answers

use Sub::ScopeFinalizer qw( scope_finalizer );

{
   my $old_foo = $foo;
   my $guard = scope_finalizer { $foo = $old_foo };

   $foo = "oof";

   say $bar{ foo }->$*;  # oof
}

say $bar{ foo }->$*;  # foo

Since you're using 5.36, you could forgo the module in lieu of an experimental feature added that version.

use experimental qw( defer );

{
   my $old_foo = $foo;
   defer { $foo = $old_foo };

   $foo = "oof";

   say $bar{ foo }->$*;  # oof
}

say $bar{ foo }->$*;  # foo
like image 110
ikegami Avatar answered Dec 31 '25 00:12

ikegami


Without using any extra modules:

use v5.36;
use warnings;

our $foo = 'foo';
our %bar = (
  foo => \$foo,
  baz => 'baz',
);

{
  local $foo = 'oof';
  local $bar{foo} = \$foo;
  print "<$foo ${$bar{foo}} $bar{baz}>";
}

print "<$foo ${$bar{foo}} $bar{baz}>";

prints <oof oof baz><foo foo baz>.

You can localize a single hash entry even if the hash is lexical (i.e. created as my %bar), but you can not localize a lexical scalar. The local built-in replaces the variable itself, not just its value, so $bar{foo} continues to refer to the original $foo.

like image 38
user20284150 Avatar answered Dec 30 '25 22:12

user20284150



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!