develooper Front page | perl.perl5.porters | Postings from January 2022

Re: Can't localize lexical variable $x at ...

Thread Previous | Thread Next
Paul "LeoNerd" Evans
January 25, 2022 15:47
Re: Can't localize lexical variable $x at ...
Message ID:
On Tue, 25 Jan 2022 13:20:17 +0000 wrote:

> Why can't we? I think I might have known the answer once, but if I did
> I no longer recall it.
> I think of local() as "temporarily replace the value at this lvalue
> with a new value, restore it at the end of the current lexical scope".
> This is hugely useful in many situations that would otherwise require
> more and slower code with much more opportunity for error.

People often think of `local` as being equivalent to saving the old
value of a variable, assigning a new value, and arranging to assign the
new value back in. Perhaps equivalent to this using our new `defer`

      my $saved_VAR = $VAR;
      defer { $VAR = $saved_VAR; }
      $VAR = $new;


That's not really how it works at all though - don't forget that
`local` is a very old Perl feature that massively predates `my`
variables. In fact, `local` isn't about values but about variables.

What `local` really does is temporarily moves a *variable* out of the
way, assigning a new one into its place, to be restored back again.
Variables themselves can only be moved around where they exist by
reference - as members of the symbol table (i.e. `our` variables), or
elements of aggregate structures (arrays and hashes). Because regular
lexical scalars do not have this one-layer-distant referencing effect,
they cannot be moved out of the way by `local`.

This distinction isn't often visible, but it does come up for example
when you consider `tie`, or other magics applied to variables.

> Is there a technical reason why it would not be possible to implement?
> Or is it that we're worried it would be confusing for users? Or is it
> only that way back when (around 5.0, I guess) nobody thought it would
> be useful?
> Is it something we would ever consider changing?

Yes and no.

Since it's detected at compiletime, it would be quite easy for the
parser to implement a totally different kind of `local`isation - one
that acts on values - when dealing with lexical variables. That may
confuse users, because it would act differently for the purposes of

My preference would be to add a new keyword (because "local" is a
terrible name anyway) to have the effect of temporarily assigning a new
*value* to any lvalue expression, and arranging for its old value to be
restored again at end of scope. In fact I already wrote a module to
provide a `dynamically` keyword doing just that:

As compared `local` it has three key differences:

  1) Can `dynamically` modify a regular lexical variable

  2) Can `dynamically` modify any lvalue-returning function or method.
     Very handy for accessor-type methods on objects:

       dynamically $logger->level = LOG_DEBUG;

  3) Interacts with the `async/await` syntax provided by
     Future::AsyncAwait, to properly swap the values around when context

       async sub f {
         dynamically $logger->level = LOG_DEBUG;

         await some_operation();

         $logger->print( "Still in debug level here" );

Bringing this keyword into perl core would be easy enough for the first
two points, but the third would be a tough sell because it first
depends on having async/await implemented in core. Arguing that into
perl core at the moment would be a Fun and Exciting challenge ;)

Paul "LeoNerd" Evans      |  |

Thread Previous | Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About