develooper Front page | perl.perl5.porters | Postings from August 2021

Re: `local` on lexicals

Thread Previous | Thread Next
From:
shmem
Date:
August 10, 2021 00:03
Subject:
Re: `local` on lexicals
Message ID:
alpine.DEB.2.21.2108091657540.4388@mgm-net.de
From the keyboard of Paul "LeoNerd" Evans [09.08.21,15:19]:

> Perl currently does not permit this:
>
>  $ perl -E 'my $x = 123; { local $x = 456; say $x }'
>  Can't localize lexical variable $x at -e line 1.

This opens a tin of worms, the tin being "scoping" and the worms "rules".

People already have a hard time grokking the differences between local,
package global and "global global" scope, the differenres between "my"
and "our" and the aliasing effect of "our" in a multiple package file.

Quick, what would sub foo print here?

     my $x = "outer";

     if (1) {
 	my $x = "cond inner";
 	foo();
     }

     sub foo {
 	print "$x\n";
     }

And what would it print if that line were in place?

 	local $x = "cond inner";

> Various reasons for this, mostly around "ugh, but local moves the
> variable, not the value". The vast majority of users don't want to use
> it like that though - they care more about the value, the effect of
> temporarily assigning a new value to the variable. Moving the variable
> out of a package, hash or array is basically equivalent to saving the
> value anyway, so most people don't notice the difference. This explains
> why it doesn't work on plain lexicals.

The main difference between lexical my variables and localized globals
is their behavior in space vs. time in a programmer's view, not so much
the difference between moving away the variable or the value.
Lexicals are bound to a scope, e.g. a block i.e. in space, localized
variables are visible in the entire code path starting from where the
localizing took place, until its conclusion.

Said otherwise, local is for localizing and aliasing a global, whereas
"my" says: "this is mine, it pertains to here" and to pass it around
you have to explicitly do so, as parameter to a subroutine, taking a
ref from it or whatever.

A "local my $foo" blurs that difference and introduces a "timely" scoping
for lexicals. Or wouldn't it? Anyways, aliasing a lexical would need another
metaphor and a different keyword than "local". Perhaps "alias"?

"local" is about localizing a global; aliasing a lexical is a different
thing, and

> The upshot is that it's not very convenient. Perhaps back in the 5.6
> era that wasn't too bad - there weren't really any situations where
> localizing a lexical would make much sense. But in more modern
> scenarios there are two big cases that come to mind:
>
>  1) aliased lexicals:
>
>    $ perl -E 'use experimental qw(declared_refs refaliasing);
>       my @arr = (qw( a b c ));
>       my \$a1 = \$arr[1];
>       local $a1 = "d";'
>    Can't localize lexical variable $a1 at -e line 1.
>
>  2) Object::Pad instance slots:
>
>    $ perl -MObject::Pad -E 'class Thing {
>       has $x;
>       method m { local $x = 123 }
>    }'
>    Can't localize lexical variable $x at -e line 1.
>
> I wonder.. since we have save_item() these days, whether `local on a
> lexical` should just use that. If it did then both of these cases would
> DWIM.
>
> At this point I'll state my interest: I've been converting more of my
> existing Perl code to using Object::Pad, and while almost everything
> comes out looking a lot neater, there's one slight akwardness in code
> that currently does
>
>  sub m
>  {
>    my $self = shift;
>    local $self->{something} = 123;
>    $self->othermethod;
>  }
>
> I can't just write this as
>
>  method m
>  {
>    local $something = 123;
>    $self->othermethod;
>  }
>
> due to theabove problem. There isn't in fact a neat way to write this.
>
> I did create Syntax::Keyword::Dynamically to solve this, among other
> problems; but it seems a bit heavyweight to drag it in just for this.
>
>  https://metacpan.org/pod/Syntax::Keyword::Dynamically
>
>

0--gg-

-- 
_($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                               /\_¯/(q    /
----------------------------  \__(m.====·.(_("always off the crowd"))."·
");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About