In short, all operations that default to $_ will default to the lexical
version of $_ if there is one in scope; else they will use (as usual)
the global $::_. For example, the following snippet will print "1221":
sub f { print };
$_ = 1;
{ my $_ = 2; f; /(.)/; print; print $1; }
print;
This is backwards-compatible, since the new behaviour is only trigerred
with a C<my $_> declaration (which is currently a compile-time error.)
In a block where $_ is lexicalized, you can "restore" access to the global
$_ simply by declaring C<our $_>.
The benefits are twofold, from a language point of view :
1. You can now use a lexical $_ without any effect at distance, without
losing any conciseness
2. Using C<my $_> gives you a pristine undefined unmagical value in $_.
This is not the case with C<local $_>, which retains any magic that
$_ could have been bound to previously (causing obscure bugs.)
There is one unresolved issue :
Inside a map or a grep the global $_ is still used as an iterator (this
is not modified by this patch.) Practically, this means that map or grep
are unusable when a lexical $_ is in scope. There are two ways to fix
this : (a) use the lexical $_ (if available) as an iterator, (b) compile
the code inside the map/grep block to always use $::_. I haven't
made up my mind about the best solution yet. Opinions welcome.
I need also to silence the warning produced by C<our $_; my $_;>
("my" variable $_ masks earlier declaration in same scope) and similar
ones. They are pointless.
Please find my patch and a minimal test file below.
This is implemented by modifying the optree at compile-time, so there
is no run-time impact for code that doesn't use this feature. (Code that
does use it is likely to run faster, because access to pads is faster than
access to globals.)
Index: pp.c
===================================================================
--- pp.c (revision 3049)
+++ pp.c (working copy)
@@ -680,6 +680,8 @@ PP(pp_trans)
if (PL_op->op_flags & OPf_STACKED)
sv = POPs;
+ else if (PL_op->op_private & OPpTARGET_MY)
+ sv = GETTARGET;
else {
sv = DEFSV;
EXTEND(SP,1);
Index: toke.c
===================================================================
--- toke.c (revision 3047)
+++ toke.c (working copy)
@@ -6518,7 +6518,8 @@ S_scan_trans(pTHX_ char *start)
New(803, tbl, complement&&!del?258:256, short);
o = newPVOP(OP_TRANS, 0, (char*)tbl);
- o->op_private = del|squash|complement|
+ o->op_private &= ~OPpTRANS_ALL;
+ o->op_private |= del|squash|complement|
(DO_UTF8(PL_lex_stuff)? OPpTRANS_FROM_UTF : 0)|
(DO_UTF8(PL_lex_repl) ? OPpTRANS_TO_UTF : 0);
Index: opcode.pl
===================================================================
--- opcode.pl (revision 3047)
+++ opcode.pl (working copy)
@@ -493,9 +493,9 @@ regcreset regexp internal reset ck_fun
regcomp regexp compilation ck_null s| S
match pattern match (m//) ck_match d/
qr pattern quote (qr//) ck_match s/
-subst substitution (s///) ck_null dis/ S
+subst substitution (s///) ck_match dis/ S
substcont substitution iterator ck_null dis|
-trans transliteration (tr///) ck_null is" S
+trans transliteration (tr///) ck_match is" S
# Lvalue operators.
# sassign is special-cased for op class
Index: op.c
===================================================================
--- op.c (revision 3047)
+++ op.c (working copy)
@@ -155,11 +155,11 @@ Perl_allocmy(pTHX_ char *name)
{
PADOFFSET off;
- /* complain about "my $_" etc etc */
+ /* complain about "my $<special_var>" etc etc */
if (!(PL_in_my == KEY_our ||
isALPHA(name[1]) ||
(USE_UTF8_IN_NAMES && UTF8_IS_START(name[1])) ||
- (name[1] == '_' && (int)strlen(name) > 2)))
+ (name[1] == '_' && (*name == '$' || (int)strlen(name) > 2))))
{
if (!isPRINT(name[1]) || strchr("\t\n\r\f", name[1])) {
/* 1999-02-27 m...@plover.com */
@@ -1673,6 +1673,7 @@ OP *
Perl_bind_match(pTHX_ I32 type, OP *left, OP *right)
{
OP *o;
+ bool ismatchop = 0;
if (ckWARN(WARN_MISC) &&
(left->op_type == OP_RV2AV ||
@@ -1697,10 +1698,14 @@ Perl_bind_match(pTHX_ I32 type, OP *left
no_bareword_allowed(right);
}
- if (!(right->op_flags & OPf_STACKED) &&
- (right->op_type == OP_MATCH ||
- right->op_type == OP_SUBST ||
- right->op_type == OP_TRANS)) {
+ ismatchop = right->op_type == OP_MATCH ||
+ right->op_type == OP_SUBST ||
+ right->op_type == OP_TRANS;
+ if (ismatchop && right->op_private & OPpTARGET_MY) {
+ right->op_targ = 0;
+ right->op_private &= ~OPpTARGET_MY;
+ }
+ if (!(right->op_flags & OPf_STACKED) && ismatchop) {
right->op_flags |= OPf_STACKED;
if (right->op_type != OP_MATCH &&
! (right->op_type == OP_TRANS &&
@@ -1801,7 +1806,15 @@ Perl_block_end(pTHX_ I32 floor, OP *seq)
STATIC OP *
S_newDEFSVOP(pTHX)
{
- return newSVREF(newGVOP(OP_GV, 0, PL_defgv));
+ I32 offset = pad_findmy("$_");
+ if (offset == NOT_IN_PAD || PAD_COMPNAME_FLAGS(offset) & SVpad_OUR) {
+ return newSVREF(newGVOP(OP_GV, 0, PL_defgv));
+ }
+ else {
+ OP *o = newOP(OP_PADSV, 0);
+ o->op_targ = offset;
+ return o;
+ }
}
void
@@ -5533,7 +5546,15 @@ Perl_ck_sassign(pTHX_ OP *o)
OP *
Perl_ck_match(pTHX_ OP *o)
{
- o->op_private |= OPpRUNTIME;
+ if (o->op_type != OP_QR) {
+ I32 offset = pad_findmy("$_");
+ if (offset != NOT_IN_PAD && !(PAD_COMPNAME_FLAGS(offset) & SVpad_OUR)) {
+ o->op_targ = offset;
+ o->op_private |= OPpTARGET_MY;
+ }
+ }
+ if (o->op_type == OP_MATCH || o->op_type == OP_QR)
+ o->op_private |= OPpRUNTIME;
return o;
}
Index: op.h
===================================================================
--- op.h (revision 3047)
+++ op.h (working copy)
@@ -135,9 +135,11 @@ Deprecated. Use C<GIMME_V> instead.
#define OPpTRANS_TO_UTF 2
#define OPpTRANS_IDENTICAL 4 /* right side is same as left */
#define OPpTRANS_SQUASH 8
-#define OPpTRANS_DELETE 16
+ /* 16 is used for OPpTARGET_MY */
#define OPpTRANS_COMPLEMENT 32
#define OPpTRANS_GROWS 64
+#define OPpTRANS_DELETE 128
+#define OPpTRANS_ALL (OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF|OPpTRANS_IDENTICAL|OPpTRANS_SQUASH|OPpTRANS_COMPLEMENT|OPpTRANS_GROWS|OPpTRANS_DELETE)
/* Private for OP_REPEAT */
#define OPpREPEAT_DOLIST 64 /* List replication. */
Index: pp_hot.c
===================================================================
--- pp_hot.c (revision 3047)
+++ pp_hot.c (working copy)
@@ -1195,6 +1195,8 @@ PP(pp_match)
if (PL_op->op_flags & OPf_STACKED)
TARG = POPs;
+ else if (PL_op->op_private & OPpTARGET_MY)
+ GETTARGET;
else {
TARG = DEFSV;
EXTEND(SP,1);
@@ -1958,6 +1960,8 @@ PP(pp_subst)
dstr = (pm->op_pmflags & PMf_CONST) ? POPs : Nullsv;
if (PL_op->op_flags & OPf_STACKED)
TARG = POPs;
+ else if (PL_op->op_private & OPpTARGET_MY)
+ GETTARGET;
else {
TARG = DEFSV;
EXTEND(SP,1);
End of Patch.
#!./perl
# tests the C<my $_> feature
BEGIN {
chdir 't' if -d 't';
@INC = '../lib';
}
print "1..16\n";
my $test = 0;
sub ok ($$) {
my ($ok, $name) = @_;
++$test;
print $ok ? "ok $test - $name\n" : "not ok $test - $name\n";
}
$_ = 'global';
ok( $_ eq 'global', '$_ initial value' );
s/oba/abo/;
ok( $_ eq 'glabol', 's/// on global $_' );
{
my $_ = 'local';
ok( $_ eq 'local', 'local $_ initial value' );
s/oca/aco/;
ok( $_ eq 'lacol', 's/// on local $_' );
/(..)/;
ok( $1 eq 'la', '// on local $_' );
ok( tr/c/d/ == 1, 'tr/// on local $_ counts correctly' );
ok( $_ eq 'ladol', 'tr/// on local $_' );
{
my $_ = 'nested';
ok( $_ eq 'nested', 'local $_ nested' );
chop;
ok( $_ eq 'neste', 'chop on local $_' );
}
{
our $_;
ok( $_ eq 'glabol', 'gains access to our global $_' );
}
ok( $_ eq 'ladol', 'local $_ restored' );
}
ok( $_ eq 'glabol', 'global $_ restored' );
s/abo/oba/;
ok( $_ eq 'global', 's/// on global $_ again' );
{
my $_ = 11;
our $_ = 22;
ok( $_ eq 22, "our $_ is seen explicitly" );
chop;
ok( $_ eq 2, 'default chop chops our $_' );
/(.)/;
ok( $1 eq 2, 'default match sees our $_' );
}
If access to pads really is faster, would it be possible to make an entry
in every pad that points to the (real global) $_, so that all access to $_
were via the pad?
This is a very arm wavy question, as I've not looked at how the relevant
ops work. I'm just assuming that each pad could have a pointer to the real
$_, and up the refcount by one.
As I understand it local should still work, because it modifies the value
of $_, rather than replacing it. However, would there be a problem with
foreach [and likewise] that IIRC create a new $_ ?
Nicholas Clark
I think that it's possible to have a global or top-level our-pad that references
$_ : the equivalent of saying "our $_" at the top of each file. And then use this.
(Hmm, I have to check whether saying "our $_" with my patch correctly references
always $main::_.)
> As I understand it local should still work, because it modifies the value
> of $_, rather than replacing it. However, would there be a problem with
> foreach [and likewise] that IIRC create a new $_ ?
In other words, should the $_ created by for/map/grep always be our $_,
or should it reuse the current lexical $_ if there's one in scope ?
Open issue, as I mentioned.
I opt for the latter
--
H.Merijn Brand Amsterdam Perl Mongers (http://amsterdam.pm.org/)
using perl-5.6.1, 5.8.0, & 5.9.x, and 806 on HP-UX 10.20 & 11.00, 11i,
AIX 4.3, SuSE 8.2, and Win2k. http://www.cmve.net/~merijn/
http://archives.develooper.com/daily...@perl.org/ per...@perl.org
send smoke reports to: smokers...@perl.org, QA: http://qa.perl.org
I'm not sure pad access is faster than $_ :-)
$ time perl -e 'while ($i++ < 1000000) { $_+$_ }'
real 0m2.441s
user 0m2.438s
sys 0m0.002s
$ time perl -e 'my $j; while ($i++ < 1000000) { $j+$j }'
real 0m2.545s
user 0m2.545s
sys 0m0.000s
$_ is not fetched via the stash; there's a shortcut for it, PL_defgv.
Regards,
Adi
I bet you use a threaded perl.
With an unthreaded perl, I have the following results :
use Benchmark;
timethese (1000000, {
global => sub { $_ = "abc" ; chop; },
local => sub { local $_ = "abc" ; chop; },
my => sub { my $_ = "abc" ; chop; },
});
timethese (1000000, {
global => sub { $_ = "abc" ; /b/ },
local => sub { local $_ = "abc" ; /b/ },
my => sub { my $_ = "abc" ; /b/ },
});
Benchmark: timing 1000000 iterations of global, local, my...
global: 3 wallclock secs ( 2.31 usr + -0.02 sys = 2.29 CPU) @ 436681.22/s (n=1000000)
local: 2 wallclock secs ( 2.72 usr + 0.00 sys = 2.72 CPU) @ 367647.06/s (n=1000000)
my: 2 wallclock secs ( 1.48 usr + 0.02 sys = 1.50 CPU) @ 666666.67/s (n=1000000)
Benchmark: timing 1000000 iterations of global, local, my...
global: 3 wallclock secs ( 3.74 usr + 0.00 sys = 3.74 CPU) @ 267379.68/s (n=1000000)
local: 5 wallclock secs ( 4.16 usr + -0.01 sys = 4.15 CPU) @ 240963.86/s (n=1000000)
my: 2 wallclock secs ( 2.59 usr + 0.00 sys = 2.59 CPU) @ 386100.39/s (n=1000000)
> $_ is not fetched via the stash; there's a shortcut for it, PL_defgv.
This shortcut is only used for tr///, s/// and m//. Other ops use the
plain stash access.
This wasn't exactly relevant here, sorry.
Regards,
Adi
Well, as long as you're forced to use $_ as your map/grep iterator,
you will need such trickery... IIRC Perl 6 will fix this.
> Exactly why was it necessary to make $_ declarable in a lexical
> variable? Did I miss the conversation that led to this patch?
Sometimes people write C<local $_> when they really mean C<my $_>.
In fact you may want to check out this long thread on clp.moderated,
I got the idea mostly from there :
http://groups.google.com/groups?threadm=20040108125137.GA4868%40efn.org
There are also a few bugs in the bug database related to the unfortunate
interaction of local() with $_ when $_ is tied or when $_ is aliased to
$1. local() doesn't remove tying so you get unexpected actions at
distance.
> > There is one unresolved issue :
> > Inside a map or a grep the global $_ is still used as an iterator (this
> > is not modified by this patch.) Practically, this means that map or grep
>
> I get the feeling that somebody is going to change map and grep to use
> something akin to sort's $a and $b. This worries me.
I don't know what to reply to this; either "not at all" or "but $a and
$b in sort are already like $_ in map and grep" :)
There's a difference here. You can't write "my $_" as of perl 5.9.0,
even if you know quite well the difference between my and local, when
you're in a situation where you want a lexical scope for $_ instead of
a dynamic scope.
> Such is the case with mistaking my and local. I dare say such is the
> case when mistaking $_ for a variable that can be used in anything less
> than an implicit context. If people are mistaking my for local, or
> don't know the difference between the two, /especially/ as pertains to
> something as magical as $_, why on earth do we need to provide a patch
> for them that will change the behaviour of $_ for people whom already
> understand it?
This isn't a change, but an extension. If you aren't in a scope where
$_ has been declared with my, there is no change.
> > In fact you may want to check out this long thread on clp.moderated,
>
> I kind of have the same opinion of clp.moderated that mjd has expressed
> over and over again, which is that it is full of, well I'll just stop
> there.
>
> > http://groups.google.com/groups?threadm=20040108125137.GA4868%40efn.org
>
> If we look at the original post here, we see nothing referring directly
> to my versus local. In fact, the poster is having problems with some
> (admittedly strange) things happening to $_ outside of the scope of his
> C<for> loop. I can understad this being unexpected.
This is a long thread...
> I don't, however, think it merits changing the way such loops behave.
> In many cases when we do things as perl programmers that cause perl to
> do things we might not expect (such as making our own $a and $b), we
> get warned. Russ, in my opinion, is correct when he suggests a
> warning.
>
> Protecting the user from strange operations on $_ having strange
> results is heavy handed and un-necessary. Throwing a warning would be
> much more polite for programs unfortunately using such strangeness, and
> also would (we can hope) educate programmers who are doing such things.
> If you prefer, a deprecation might be more in order. I guess what I'm
> getting at here is that a patch is drastic.
And moreover it would be difficult to detect cases where such uses
of $_ aren't intended.
> > There are also a few bugs in the bug database related to the unfortunate
> > interaction of local() with $_ when $_ is tied or when $_ is aliased to
>
> Tying $_. Oh my. What is it these users are expecting? Are they
> honestly expecting the highly magic $_ variable to behave just like any
> other variable? Let's look at the pod for $_:
Not tying $_ directly, but having it aliased to a tied variable.
As it happens in loops.
> $ARG
> $_ The default input and pattern-searching space. The following
> pairs are equivalent:
>
>
> And yet, just a little further, we see:
>
> $a
> $b Special package variables when using sort(), see "sort" in
> perlfunc. Because of this specialness $a and $b don't need
> to
> be declared (using local(), use vars, or our()) even when
> using
> the strict vars pragma. Don't lexicalize them with "my $a"
> or
> "my $b" if you want to be able to use them in the sort() com-
> parison block or function.
>
> It seems that somebody is a lot more concerned with the use of $a and
> $b (ostensibly because they are magical and do magical things) than
> they are with the use of $_.
But neither $_, $a or $b are magical at all. That is the whole
point of my patch : as you can't guarantee, when you've localized
$_, that it *won't* be magical, this makes $_ currently mostly
unuseful for use in generic modules.
> > > I get the feeling that somebody is going to change map and grep to use
> > > something akin to sort's $a and $b. This worries me.
> >
> > I don't know what to reply to this; either "not at all" or "but $a and
> > $b in sort are already like $_ in map and grep" :)
>
> No. They really are not. The major difference between the $a and $b
> variables and $_ is that $a and $b are only used in sort. $_ is used
> all over the place. In regexes, in map, in grep, in for iterators, and
> in places I am presently forgetting. To change the behaviour of map is
> to second guess its use in all of those places. To change something
> such as $a and $b is as simple as adding a warning and a note in the
> pod.
>
> I don't see why we can't just add a warning here, and a note in the pod
> saying "This is inconsistent, and as such this particular use has been
> deprecated; it will change in 5.10."
What do you want to deprecate exactly ?
> The following patch proposes an extension to Perl 5's syntax : the
> ability to declare $_ (the well-known default scalar) as a lexical
> variable.
When I originally read this, I thought, "why does he want to do that?"
And then I remembered the weirdness of things like:
my %foo = map {
$bar = $_;
$_ => [ map { something( $bar ) } @baz ]
} @bletch;
Which I usually have to use semi-frequently. Of course, as I read
further down in your message, I realized that this is not what you
were correcting, and in fact, the case of $_ in map and grep is not
fixed.
Exactly why was it necessary to make $_ declarable in a lexical
variable? Did I miss the conversation that led to this patch?
...
> There is one unresolved issue :
> Inside a map or a grep the global $_ is still used as an iterator (this
> is not modified by this patch.) Practically, this means that map or grep
I get the feeling that somebody is going to change map and grep to use
something akin to sort's $a and $b. This worries me.
Alex
--
al...@posixnap.net
Alex J. Avriette, Unix Systems Gladiator
"Something seems to have happened to the life support system , Dave."
> > my %foo = map {
> > $bar = $_;
> > $_ => [ map { something( $bar ) } @baz ]
> > } @bletch;
> >
> > Which I usually have to use semi-frequently. Of course, as I read
> > further down in your message, I realized that this is not what you
> > were correcting, and in fact, the case of $_ in map and grep is not
> > fixed.
>
> Well, as long as you're forced to use $_ as your map/grep iterator,
> you will need such trickery... IIRC Perl 6 will fix this.
Right. My concern here is that by further obfuscating the value of $_
(by changing its value per scope), you are further complicating an
already complicated variable. Is this really necessary? See my comments
below about when it "is" necessary.
> Sometimes people write C<local $_> when they really mean C<my $_>.
And sometimes people write C<local $foo> instead of C<my $foo>. This
comes up a lot in communities of people who are often asked to answer
questions from people who are not quite up on the documentation said
community provides. The question is often posited, "How can we make
people come to us less frequently with stupid questions?"
Such is the case with mistaking my and local. I dare say such is the
case when mistaking $_ for a variable that can be used in anything less
than an implicit context. If people are mistaking my for local, or
don't know the difference between the two, /especially/ as pertains to
something as magical as $_, why on earth do we need to provide a patch
for them that will change the behaviour of $_ for people whom already
understand it?
> In fact you may want to check out this long thread on clp.moderated,
I kind of have the same opinion of clp.moderated that mjd has expressed
over and over again, which is that it is full of, well I'll just stop
there.
> http://groups.google.com/groups?threadm=20040108125137.GA4868%40efn.org
If we look at the original post here, we see nothing referring directly
to my versus local. In fact, the poster is having problems with some
(admittedly strange) things happening to $_ outside of the scope of his
C<for> loop. I can understad this being unexpected.
I don't, however, think it merits changing the way such loops behave.
In many cases when we do things as perl programmers that cause perl to
do things we might not expect (such as making our own $a and $b), we
get warned. Russ, in my opinion, is correct when he suggests a
warning.
Protecting the user from strange operations on $_ having strange
results is heavy handed and un-necessary. Throwing a warning would be
much more polite for programs unfortunately using such strangeness, and
also would (we can hope) educate programmers who are doing such things.
If you prefer, a deprecation might be more in order. I guess what I'm
getting at here is that a patch is drastic.
> There are also a few bugs in the bug database related to the unfortunate
> interaction of local() with $_ when $_ is tied or when $_ is aliased to
Tying $_. Oh my. What is it these users are expecting? Are they
honestly expecting the highly magic $_ variable to behave just like any
other variable? Let's look at the pod for $_:
$ARG
$_ The default input and pattern-searching space. The following
pairs are equivalent:
And yet, just a little further, we see:
$a
$b Special package variables when using sort(), see "sort" in
perlfunc. Because of this specialness $a and $b don't need to
be declared (using local(), use vars, or our()) even when using
the strict vars pragma. Don't lexicalize them with "my $a" or
"my $b" if you want to be able to use them in the sort() com-
parison block or function.
It seems that somebody is a lot more concerned with the use of $a and
$b (ostensibly because they are magical and do magical things) than
they are with the use of $_.
> > I get the feeling that somebody is going to change map and grep to use
> > something akin to sort's $a and $b. This worries me.
>
> I don't know what to reply to this; either "not at all" or "but $a and
> $b in sort are already like $_ in map and grep" :)
No. They really are not. The major difference between the $a and $b
variables and $_ is that $a and $b are only used in sort. $_ is used
all over the place. In regexes, in map, in grep, in for iterators, and
in places I am presently forgetting. To change the behaviour of map is
to second guess its use in all of those places. To change something
such as $a and $b is as simple as adding a warning and a note in the
pod.
I don't see why we can't just add a warning here, and a note in the pod
saying "This is inconsistent, and as such this particular use has been
deprecated; it will change in 5.10."
alex
--
al...@posixnap.net
Alex J. Avriette, Unix Systems Gladiator
Sep 25 12:52:39 buggle /bsd: wsdisplay0 at vga1: removing /dev/radio/*
> The following patch proposes an extension to Perl 5's syntax : the
> ability to declare $_ (the well-known default scalar) as a lexical
> variable.
[...]
Nice one!
The actual effect this patch has on all those thinkable (and
unthinkable) edge-cases is hard to predict. I'd really like to see this
one go into 5.9 so that it can be more thoroughly tested. That would
leave enough time to fix potential problems with it or remove it again
for 5.10 as a last resort.
Tassilo
--
$_=q#",}])!JAPH!qq(tsuJ[{@"tnirp}3..0}_$;//::niam/s~=)]3[))_$-3(rellac(=_$({
pam{rekcahbus})(rekcah{lrePbus})(lreP{rehtonabus})!JAPH!qq(rehtona{tsuJbus#;
$_=reverse,s+(?<=sub).+q#q!'"qq.\t$&."'!#+sexisexiixesixeseg;y~\n~~dddd;eval
If it gets approval from the powers that be, I'm considering adding an option
to run the coretests with a 'my $_' sticked on top of the .t files, and
turning every 'local $_' in 'local our $_'. (A source filter might be
in order for that task.)
I haven't given it much thought yet, but my main concern is closures.
Since $_ is used so often both explicity and implicitly, I think there's
a good chance of people accidently creating closures, eg
sub f {
my $_;
...
return sub { $_= shift; /.../ } # unintented closure!
}
Also, should the presence of an op which uses $_ implicty create a
closure?
sub f {
my $_;
...
return sub { /.../ } # closure ???
}
and if that's a closure, then so is f below:
my $_;
...
sub f { /.../ } # closure!
which might really trip the unwary.
But yes, I like the idea of C<my $_> in principle!
--
"Strange women lying in ponds distributing swords is no basis for a system
of government. Supreme executive power derives from a mandate from the
masses, not from some farcical aquatic ceremony."
-- Dennis - Monty Python and the Holy Grail.
Yes, that's a closure. Unless you our $_.
> Also, should the presence of an op which uses $_ implicty create a
> closure?
>
> sub f {
> my $_;
> ...
> return sub { /.../ } # closure ???
> }
Likewise.
> and if that's a closure, then so is f below:
>
> my $_;
> ...
> sub f { /.../ } # closure!
>
> which might really trip the unwary.
No, because it's not an anonymous sub. Right?
Hmmm, I really must finish my 'closure' doc. Yep, its a closure (by my
definition!). A closure is any sub that refers to an outer lexical. Anon
subs just happen to be a more interesting case. Here, inc() and dec() are
closures:
{
my $counter = 0;
sub inc { $counter++ }
sub dec { $counter-- }
}
(Note that the lifetime of $counter is extended because it's captured by
the two named subs.)
Dave.
--
Standards (n). Battle insignia or tribal totems.
That's right.
The more I think about it, the more I prefer the option to have map/grep/for
always use $::_ as an iterator.
I don't know what opinion you might be referring to, so I hope nobody
else will draw any conclusions about what you might have meant here.
> Tying $_. Oh my. What is it these users are expecting?
Programs are usually written by more than once person. One problem
Rafael is trying to solve arises because $_ is tied, not intentionally
by a single programmer, but because of a bizarre interaction between
things that several programmers have done. Here is an example.
Programmer A has written
tie @array, 'SOMECLASS', ...;
funcB(\@array);
Programmer B has written funcB():
sub funcB {
my $aref = shift;
for (@$aref) {
funcC(...);
}
}
Programmer C has written funcC():
sub funcC {
my @args = @_;
local $_;
while (<FH>) {
...
}
}
Nobody here has done anything even a little out of the ordinary. But
unbeknownst to anyone, programmer C's innocent attempt to use $_ as
the target of "while (<FH>)" has unexpectedly invoked
SOMECLASS::STORE.
This kind of bug cannot be caught by static analysis. The entire
program might work properly a thousand times, and then fail
mysteriously the next time it was run. The behavior of
SOMECLASS::STORE is entirely unbounded; the program might accidentally
erase the filesystem the 1001st time it is run.
Programmer C thought that using $_ in funcC was safe, because of the
'local $_' directive. But it *isn't* safe, because it *also* calls
SOMECLASS::STORE; the problem is not even altered.
To be safe, every programmer who uses $_ in any function anywhere must
write something like this:
sub funcC {
my @args = @_;
local *_;
while (<FH>) {
...
}
}
so we need a massive education campaign to get people, including all
CPAN module authors, to stop using 'local $_' and to start using
'local *_' instead.
With Rafael's patch, we have instead a massive education campaign to
get people to stop using 'local $_' and to start using 'my $_'
instead.
Or we can put a warning on about 85% of all uses of $_ anywhere.
Or we can continue to accept the problem.
I like Rafael's solution a lot. I think that the education campaign
will be painless compared with the one we need if his solution is not
adopted. I also think it will be much more nearly effective.
That does not mean it is the best possible solution, but I think it is
much better than what we have now.
Being explained the _real_ reason for Rafael's patch now, I think I
like Rafael's approach for three reasons:
1. I never liked local(). It's current use feels like using a
side-effect from Perl 4 to me. my $_ feels much more natural to me.
2. "local *_" will be cargo-cult for very _many_ people. If you
started programming Perl in the past 4 years, you should not have
been exposed to local() as an "ordinary" Perl programmer, I don't
think. Globs are very mysterious things to many Perl programmers.
"local *_" will be just a magic invocation to these programmers.
3. There will be no globs in Perl 6 as such: do we want to add an
idiom at this stage that uses globs?
Argh... I will now have to go through all of my CPAN modules and check... ;-(
Liz
I thought unpack used it in blead, also.
It used to. I fixed it :)
don't you have explicitly fix your code to use it if you have used $_ in it?
$_ =~ /foo/ for 1..3;
won't work now?
what if you have a nested call?
for (1..3) {
print "$_\n";
my @x = grep /\d/, 5..6;
print "$_\n";
}
would it now affect $_ of the outer loop (of course replace $_ with $::_?
__________________________________________________________________
Stas Bekman JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/ mod_perl Guide ---> http://perl.apache.org
mailto:st...@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org http://ticketmaster.com
This is all cool, but you forget about one problem. 'my $_' won't work with
older perls. Since most CPAN modules have to work with older perls the
compaign A (local *_) sounds more practical to me. And compaign B (my $_)
totally impractical, unless you can afford to require 5.8.4 and higher, which
will probably take a few years or so. Of course the situation is different
with in-house code bases, where you don't have to support older perls.
I think the best education compaign would be: to never use $_ when you call a
sub from a loop. You never know whether a called sub handles $_ correctly.
It's so much simpler to educate people to say:
sub funcB {
my $aref = shift;
for my $ref (@$aref) {
funcC($ref, ...);
}
}
than explaining what 'local *_' means.
or, better said :
/foo/ for 1..3;
This won't change. And :
sub f { /foo/ } f() for 1..3;
won't change.
The issue is more with things like :
sub f { /foo/ } my $_; f() for 1..3;
Should the for loop iterate over $::_ (thus transmitting $_ to f) or not ?
> won't work now?
>
> what if you have a nested call?
>
> for (1..3) {
> print "$_\n";
> my @x = grep /\d/, 5..6;
> print "$_\n";
> }
>
> would it now affect $_ of the outer loop (of course replace $_ with $::_?
I'd rather not. If we assume that the 1st and 3rd $_ are my'ed, and that
grep iterates over a local $::_.
ok, so you do localize $::_, for some reason I thought you suggested to use
unlocalized global. silly me.
Of course not, this $::_ will be an alias to each list element in turn, so it
will retain their magic. However it will not have magic of its own. I assume
that's what you meant :)
> > I don't see why we can't just add a warning here, and a note in the pod
> > saying "This is inconsistent, and as such this particular use has been
> > deprecated; it will change in 5.10."
>
> What do you want to deprecate exactly ?
Actually, I was going to suggest the deprecation of 'local $_' and 'my $_'
entirely. However, after reading MJD's response, I understand the problem
much better, and agree witht he approach being taken.
Alex
... which is already the case in the current implementation ...
> so it
> will retain their magic. However it will not have magic of its own. I assume
> that's what you meant :)
There is another case where $_ is aliased behind the scenes :
in /(?{...})/ blocks, it's aliased to the string the regular expression
is matching against.
AFAIK this is not documented, so I'll maybe add a short note for this
in perlre.pod.
meaning that we cannot do
my ($x, $y) = unpack "sL";
anymore?
D'uh! I liked that!
--
H.Merijn Brand Amsterdam Perl Mongers (http://amsterdam.pm.org/)
using perl-5.6.1, 5.8.0, & 5.9.x, and 806 on HP-UX 10.20 & 11.00, 11i,
AIX 4.3, SuSE 8.2, and Win2k. http://www.cmve.net/~merijn/
http://archives.develooper.com/daily...@perl.org/ per...@perl.org
send smoke reports to: smokers...@perl.org, QA: http://qa.perl.org
It's still there, it just implicitly adds a gvsv(*_) unstead of using defgv.
Most things work this way, tr, s, and m are the exceptions.
Pheew, thanks
Seems ok (if a little hard to document) as long as my $_; ...; print
":$_:" for LIST; actually uses the global in the for as well as
aliasing to it.
> ... which is already the case in the current implementation ...
>
> > so it
> > will retain their magic. However it will not have magic of its own. I assume
> > that's what you meant :)
>
> There is another case where $_ is aliased behind the scenes :
> in /(?{...})/ blocks, it's aliased to the string the regular expression
> is matching against.
>
> AFAIK this is not documented, so I'll maybe add a short note for this
> in perlre.pod.
Is that desired behaviour? What's the reason for it?
It's very clearly intentionnally coded : search regexec.c for :
/* Make $_ available to executed code. */
This is from IlyaZ, change #2367.
But this probably killed the performace improvement that was an
argument for the patch at the time ...
Regards,
Adi
Sometimes I prefer consistency and maintainability over optimizations.
And now we have a wide open field of new speed performance gains with my $_;