muthm has asked for the wisdom of the Perl Monks concerning the following question:
I have experienced an unexpected behavior of 'local'.
I am trying to attach the scope of the value of a global variable to the current lexical block (e.g. a function),
meaning that upon exit of that block, the previous value is restored.
I think this is exactly the intended use case for local.
The reason why I am doing this is to create a module with subroutines for selective debugging output. Kind of like this:
which creates this output:#!/usr/bin/env perl use v5.20; use warnings; use feature 'signatures'; no warnings 'experimental::signatures'; # ------ Debugging function definition: our %debug; our $d_area = "(default)"; sub dsay( @args ) { return unless $debug{ uc $d_area } || $debug{'ALL'}; my $prefix = $d_area ne "(default)" ? "DEBUG $d_area: " : "DEBUG: "; say $prefix, @args; } # ------ Application program: sub common_sub { say "call to common sub (d_area is $d_area)"; dsay "debugging output from common_sub"; } sub one { say "call to one:"; local $d_area = "one"; dsay "debugging output from one"; common_sub; dsay "more debugging output from one"; } sub two { say "call to two:"; local $d_area = "two"; dsay "debugging output from two"; common_sub; dsay "more debugging output from two"; } # Switch on debugging for area 'two' # (I'll use command line switches with Getopt::Long later). $debug{TWO} = 1; say "hello from main"; dsay "debugging output from main"; one; two;
hello from main call to one: call to common sub (d_area is one) call to two: DEBUG two: debugging output from two call to common sub (d_area is two) DEBUG two: debugging output from common_sub DEBUG two: more debugging output from two
This works perfectly.
Note that the debugging output of common_sub depends on the localized value of the $d_area variable.
But now I want to put the debugging output function and variables into a module, export everything correctly, like this:
and replace the definitions in the main program by a simple# # Dsay.pm # package Dsay; use parent 'Exporter'; our @EXPORT = qw( %debug $d_area dsay ); our %debug; our $d_area = "(default)"; sub dsay( @args ) { return unless $debug{ uc $d_area } || $debug{'ALL'}; my $prefix = $d_area ne "(default)" ? "DEBUG $d_area: " : "DEBUG: "; say $prefix, @args; } 1;
The result is that I don't get any debugging output anymore.use Dsay;
I understand that importing $d_area creates an entry in the symbol table of the importing module (here: main), which references the variable in the Dsay module.
And after a long while of contemplating (and debugging, and reading, and experimenting)
I think I also understand that local $d_area = "..."; creates a new temporary variable to hold the new value,
and — also temporarily — changes the $d_area symbol
to be a reference to that new variable (and value).
The symbol that is changed is the one in the current package's symbol table, because $d_area is unqualified.
Which means that the symbol — and the value! — in the Dsay module is completely unaffected,
and not substituted!
This explains the unexpected behavior.
Surely, to remedy this, I could use
in all places, but I would have liked to avoid to use the fully qualified name, for easier typing and faster debugging.local $Dsay::d_area = '...';
After all, the unqualified $d_area refers to the variable within the Dsay module,
which menas that any change done here is seen there, and any change done there is seen here.
But local cuts that correspondence!
Do the monks know of any incantation (or magic spell?) so that local $d_area modifies the original imported variable,
not only the local one?
Could there be any benefit in adding an explicit import function to the Dsay module,
and/or playing around with explicit variable references like \$Dsay::d_area to that effect?
|
---|