On Tue, 25 Jan 2022 13:20:17 +0000
hv@crypt.org 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`
blocks:
{
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
tie/magic.
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:
https://metacpan.org/pod/Syntax::Keyword::Dynamically 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
switching:
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
leonerd@leonerd.org.uk |
https://metacpan.org/author/PEVANS http://www.leonerd.org.uk/ |
https://www.tindie.com/stores/leonerd/