develooper Front page | perl.perl5.porters | Postings from March 2013

Re: Salvaging lexical $_ from deprecation

Thread Previous | Thread Next
From:
Lukas Mai
Date:
March 3, 2013 09:34
Subject:
Re: Salvaging lexical $_ from deprecation
Message ID:
5133191C.30900@web.de
On 20.02.2013 08:23, Rafael Garcia-Suarez wrote:
> How would you expect this flavour of try-catch work in all cases
> *without* a proper lexical $_? how would you guarantee without it that
> the $_ you're using in the catch block hasn't been clobbered from
> anywhere else ? (Remember the old $@ woes with eval and destructors.
> $@ is another example of a variable that should be lexicalized, but
> isn't, and had caused much bugs because of that.)

I don't think even $@ should be lexicalized. For example in C++ the 
current exception is also dynamically inspectable:

void foo() {
   try {
     throw;  // rethrow current exception, like 'die $@'
   } catch (Tired &e) {
     // do stuff with e
   } catch (Exhausted &e) {
     // do stuff with e
   }
   // pass through all other exceptions
}

void bar() {
   try {
     baz();  // may throw
   } catch (...) {  // catch all
     foo();
     // foo() has access to the exception thrown by baz().
     // This is not lexical in any way.
   }
}

> Really, it sounds like a proper (improved) lexical $_ is a solution,
> and a quite elegant one, as possible as it can be; not a problem.

Lexical $_ causes action at a lexical distance. If you have a "$_ 
consumer" such as 'sub { $_ }' or 'any { $_ > 5 } @foo' or 'try { foo() 
} catch { warn $_ }' somewhere (e.g. deeply nested or at the bottom of 
the file), and you add 'my $_' anywhere in its parent scopes (e.g. near 
the top of the file), the $_ reference in the consumer will latch onto 
the lexical variable, which silently changes the meaning of the code.

> As I mentioned before we need a mechanism to mimic map and grep for
> XSUBs (like UNDERBAR, but that works) and for subs. What we don't need
> is to throw the baby away even before having tried to put water in the
> tub.

I don't think mimicking map/grep is a good idea because they're actually 
crazy. (I had to read up on their behavior because lexical $_ just 
doesn't make sense in my mental model of Perl.)

% perl -wE 'my $_ = "a"; my @fs = map { sub { $_ } } 1, 2, 3; say $_->() 
for @fs; say'
Use of my $_ is experimental at -e line 1.
1
2
3
a

What's happening here is that map injects a lexical $_ into its argument 
block, i.e. there's an implicit 'my $_ = <current value>;' after 'map {'.

Except that's not quite true because the inner $_ is actually an alias 
to the current value, not a copy. (I don't think you can do this with 
"normal" lexical variables ('my *_ = \<current value>;' or something?).)

So each of the 'sub { $_ }' functions ends up closing over a different 
$_ variable, which is why every element of @fs returns a different value 
when called. And of course the original $_ is completely unaffected by 
this despite there being only one 'my $_' declaration in the program, 
which normally means you're only dealing with one variable with a given 
name. But here you get four for the price of one.

This behavior (map implicitly creating more lexical $_'s in its argument 
block) is triggered by there being a 'my $_' anywhere in map's scope.

And now you want to give XS and Perl subs access to the same kind of 
thing. I just don't think it's a good idea.

-- 
Lukas Mai <l.mai@web.de>

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