#!/usr/bin/perl -w
use strict;
sub readZip() {
open FH, '/dev/null';
while (<FH>) { print "Got something from /dev/null!\n"; last; }
close FH;
}
my $x = 'hi';
for ($x) { readZip(); }
print "Undefined!\n" unless defined $x;
__END__
(I'm using perl 5.6.1, but I believe it behaves the same in other versions.)
I distilled this from a script where the subroutine was in a separate
package (and actually did something useful). The for loop in the main
program was one of the recommended idioms for implementing a switch on the
value of $x.
Thanks,
Ted Hopp
t...@newslate.com
> Why does the following program print "Undefined!"? Shouldn't the
> subroutine leave the value of $x alone? (I can understand it clobbering
> $_, but $x?)
for creates aliases for the data it loops over, rather than creating
copies. This is normally for the sake of convenience, so that you can
(for instance) modify arrays inside a for loop as you iterate across them
and have those modifications stick, but sometimes it bites you.
In perlsyn, there is:
If any element of LIST is an lvalue, you can modify it by modifying
VAR inside the loop. Conversely, if any element of LIST is NOT an
lvalue, any attempt to modify that element will fail. In other words,
the "foreach" loop index variable is an implicit alias for each item
in the list that you're looping over.
So what's happened here is that in:
> for ($x) { readZip(); }
$_ becomes an alias for $x, which means that when the subroutine is
called:
> sub readZip() {
> open FH, '/dev/null';
> while (<FH>) { print "Got something from /dev/null!\n"; last; }
> close FH;
> }
and it overwrites $_ with the <FH> expression, that data is stored into $_
and therefore into $x since during that for loop, $_ is an alias for $x.
--
#!/usr/bin/perl -- Russ Allbery, Just Another Perl Hacker
$^=q;@!>~|{>krw>yn{u<$$<[~||<Juukn{=,<S~|}<Jwx}qn{<Yn{u<Qjltn{ > 0gFzD gD,
00Fz, 0,,( 0hF 0g)F/=, 0> "L$/GEIFewe{,$/ 0C$~> "@=,m,|,(e 0.), 01,pnn,y{
rw} >;,$0=q,$,,($_=$^)=~y,$/ C-~><@=\n\r,-~$:-u/ #y,d,s,(\$.),$1,gee,print
Your for loop uses $_ as the loop variable.
* However * the loop variable in a "for[each]" loop is also set to be an
alias for the thing being looped over.
So, in your case $_ is an alias for $x, so when <FH> clobbers $_ then it
also clobbers $x.
You might call it a gotcha, but it is is also the thing that allows a
foreach loop to loop over a set of things and update them, e.g.
foreach (@things)
{ s/one/two/; # this updates each thing in @things
}
You could say something like "for my $x ($x)..." or "for ($x) { local $_
...." though these might break your switch idiom.
>So what's happened here is that in:
>
>>for ($x) { readZip(); }
>
>$_ becomes an alias for $x, which means that when the subroutine is
>called:
>
>> sub readZip() {
>> open FH, '/dev/null';
>> while (<FH>) { print "Got something from /dev/null!\n"; last; }
>> close FH;
>> }
>
>and it overwrites $_ with the <FH> expression,
I've never understood why 'while (<FH>)' should clobber the value of
$_ outside the loop body. Surely it would make more sense to have a
new $_ inside the loop, just as 'foreach (<FH>)' would.
FWIW I think the above code should trigger a warning. It's okay, if a
bit bizarre, for 'while (<FH>)' to change the $_ inside the same
subroutine. But changing the caller's value of $x is really
unreasonable.
--
Ed Avis <e...@membled.com>
> I've never understood why 'while (<FH>)' should clobber the value of $_
> outside the loop body. Surely it would make more sense to have a new $_
> inside the loop, just as 'foreach (<FH>)' would.
I mostly agree with you, but this idiom has been around for so long in
Perl and there's so much code that relies on this that I really can't see
it being changed in anything short of Perl 6.
> FWIW I think the above code should trigger a warning. It's okay, if a
> bit bizarre, for 'while (<FH>)' to change the $_ inside the same
> subroutine. But changing the caller's value of $x is really
> unreasonable.
This is an interesting point, although the warning seems very special-case
and gimmicky to me. I'm not sure how one could coherently explain that in
the documentation.
>>I've never understood why 'while (<FH>)' should clobber the value of $_
>>outside the loop body.
>>FWIW I think the above code should trigger a warning. It's okay, if
>>a bit bizarre, for 'while (<FH>)' to change the $_ inside the same
>>subroutine. But changing the caller's value of $x is really
>>unreasonable.
>
>This is an interesting point, although the warning seems very
>special-case and gimmicky to me.
Maybe, but the behaviour it warns about is so bizarre and so puzzling
to debug if you're not aware of it. I called foo() and the value of
$x changed - but I didn't pass $x to foo(), nor is it global - WTF?
>I'm not sure how one could coherently explain that in the
>documentation.
I was thinking of a warning like
Caller's lexical $x changed inside foo() at program line 123
(X) Because foo() uses $_, and you called it inside a 'for' or
'foreach' block using $_ as the variable, it will affect
whatever you were looping over. This happens whether or not
$_ is localized inside foo().
In this particular case, the variable $x is being overwritten.
What you'd find difficult to coherently explain is why
local $_;
does not work, in that it doesn't stop changes to $_ from affecting
the caller and other scopes. This is IMHO a nasty wart on the
language and makes it awkward to use $_ safely in a subroutine.
--
Ed Avis <e...@membled.com>
> What you'd find difficult to coherently explain is why
> local $_;
> does not work, in that it doesn't stop changes to $_ from affecting the
> caller and other scopes. This is IMHO a nasty wart on the language and
> makes it awkward to use $_ safely in a subroutine.
I would, in fact, go so far as to say that that's a bug. Furthermore,
it's not one that my version of Perl manifests. Where are you seeing that
problem?
windlord:~> cat /tmp/foo
#!/usr/bin/perl
sub foo { local $_; $_ = "wrong" }
my $x = "right";
for ($x) { foo(); }
print "$x\n";
sub bar { $_ = "wrong" }
$x = "right";
for ($x) { bar(); }
print "$x\n";
windlord:~> perl /tmp/foo
right
wrong
windlord:~> perl -v
This is perl, v5.8.0 built for i386-linux-thread-multi
[...]
windlord:~> /usr/pubsw/bin/perl /tmp/foo
right
wrong
windlord:~> /usr/pubsw/bin/perl -v
This is perl, v5.6.1 built for i686-linux
[...]
>>What you'd find difficult to coherently explain is why
>
>> local $_;
>
>>does not work, in that it doesn't stop changes to $_ from affecting the
>>caller and other scopes.
What I was thinking of was something like
#!/usr/bin/perl
use warnings;
use strict;
package My_scalar;
require Tie::Scalar;
our @ISA = ('Tie::StdScalar');
sub STORE { print "storing\n" }
package main;
my $s;
tie $s, 'My_scalar';
$s = 'hello';
for ($s) { foo() }
sub foo {
local $_;
# Now we can use $_ for things without affecting anyone else,
# because it's localized, right?
#
$_ = 'goodbye';
}
Now that is a rather silly example, I admit, but still it illustrates
that you can't safely localize $_ (or any global variable) and assume
you are insulated from what it was set to before.
What you can do is
sub foo {
for (my $tmp) {
# Changes to $_ in here really are safe.
}
}
But that's syntactically awkward; it would be good to have
local_yes_really_i_mean_it $_;
with the same effect.
--
Ed Avis <e...@membled.com>
> What I was thinking of was something like
> #!/usr/bin/perl
> use warnings;
> use strict;
> package My_scalar;
> require Tie::Scalar;
> our @ISA = ('Tie::StdScalar');
> sub STORE { print "storing\n" }
> package main;
> my $s;
> tie $s, 'My_scalar';
> $s = 'hello';
> for ($s) { foo() }
> sub foo {
> local $_;
> # Now we can use $_ for things without affecting anyone else,
> # because it's localized, right?
> #
> $_ = 'goodbye';
> }
Well...
windlord:~> perl
my $s = 'hello';
for ($s) { foo() }
print "$s\n";
sub foo {
local $_;
$_ = 'goodbye';
}
hello
This works fine for me as long as I'm not using Tie::Scalar. So I wonder
if this isn't just a bug in tying rather than any more general problem.
It is a gaping hole in the tie()ing interface that the result of
localization is not defined. There are some
hacks^H^H^H^H^Hworkarounds possible from C, but I do not think
anything reasonable can be made from Perl.
Yes, I agree that interaction with for-aliasing is very unfortunate.
Moreover, I consider the whole idea of non-lexical aliasing completely
broken. [Backward compatibility strickes again.]
BTW, is there a category of `use warnings' which would catch
non-lexical aliasing?
Yours,
Ilya
>It is a gaping hole in the tie()ing interface that the result of
>localization is not defined. There are some
>hacks^H^H^H^H^Hworkarounds possible from C, but I do not think
>anything reasonable can be made from Perl.
I think the bigger problem is the way 'local' works - by
assignment. Better, I think, would be to rebind the variable name to
a new value during the current block and bind it back afterwards.
Not that assignment isn't sometimes useful. You might have a global
$debug_level which is in fact a tied scalar and does magic things when
assigned to. In that case 'local $debug_level = 1' does the right
thing. But this is pretty rare compared to the cases when you'd
prefer to ignore whatever scalar the variable was previously bound to.
>Yes, I agree that interaction with for-aliasing is very unfortunate.
>Moreover, I consider the whole idea of non-lexical aliasing
>completely broken. [Backward compatibility strickes again.]
>
>BTW, is there a category of `use warnings' which would catch
>non-lexical aliasing?
By 'non-lexical aliasing' do you mean aliasing something which is not
a lexically scoped variable? So
for my $v (1) { ... } # this is okay
our $global;
for $global (1) { ... } # this isn't
I'd say there could be a warning when you alias a non-lexical variable
to something magical. If it's not magical then it should be safe to
localize. So, taking $_ as the variable aliased:
for ('hello') { ... } # fine
for ([]) { ... } # also fine, it's a ref but not magic
for ($1) { ... } # dangerous - 'local $_' will break
Maybe you could take it a step further and warn only if you do the
aliasing and then go on to localize the aliased variable, or make a
subroutine call (it being assumed that the subroutine should be able
to say 'local $_' with confidence).
--
Ed Avis <e...@membled.com>
sub foo {
local $_ = 'goodbye';
print;
}
my $str = 'hello';
$str =~ /(\w+)/;
foo() for $1;
On my perl-5.8.0 this prints 'hello'; I think on later versions it
might die with an error about writing to $1. The point is that
foo()'s behaviour changes according to what the caller set $_ to, even
though foo() has tried to localize $_.
This suggests that 'local $_' is not safe to use in subroutines,
unless you want to put extra requirements on callers about what $_
should be set to when the sub is called.
--
Ed Avis <e...@membled.com>
Correct ; the fix didn't make it into 5.8.1 for maturity and backward
compatibility reasons. But bleadperl currently dies on this program with
the message "Modification of a read-only value attempted".
If you want a new variable, localize the glob :
local *_; $_ = 'goodbye';
>The point is that
>foo()'s behaviour changes according to what the caller set $_ to, even
>though foo() has tried to localize $_.
>
>This suggests that 'local $_' is not safe to use in subroutines,
>unless you want to put extra requirements on callers about what $_
>should be set to when the sub is called.
Yes. local() doesn't create a whole new variable. Magic is not touched
by local() (and that's considered to be a feature, because it's useful
for a bunch of special variables like %ENV, $/, etc.)
--
Undoubtedly is not *NIX
local() works by undef()ing, not by assignment.
> Better, I think, would be to rebind the variable name to
> a new value
"new value" has so many meanings that I'm at loss trying to guess what
you want *exactly*. And not being exact gets us back in the same mess
of unscalability - things work in simplest situation, but not in
slightly different ones. [Witness these Perl6 "specifications"...]
> Not that assignment isn't sometimes useful. You might have a global
> $debug_level which is in fact a tied scalar and does magic things when
> assigned to. In that case 'local $debug_level = 1' does the right
> thing. But this is pretty rare compared to the cases when you'd
> prefer to ignore whatever scalar the variable was previously bound to.
Again, I'm at loss whether you for or against your proposal. ;-)
> >BTW, is there a category of `use warnings' which would catch
> >non-lexical aliasing?
>
> By 'non-lexical aliasing' do you mean aliasing something which is not
> a lexically scoped variable? So
Yes.
> I'd say there could be a warning when you alias a non-lexical variable
> to something magical. If it's not magical then it should be safe to
> localize.
Then one should do the same for `while(<>)' stuff - if $_ is magical,
a warning should be issued...
> Maybe you could take it a step further and warn only if you do the
> aliasing and then go on to localize the aliased variable, or make a
> subroutine call (it being assumed that the subroutine should be able
> to say 'local $_' with confidence).
Here the situation may quickly get out of reach in the sense of
difficulty of detection such a situation.
Yours,
Ilya
That statement is ambiguous (or wrong). Magic values *are* changed
(otherwise local $ENV{PATH} would not do what people expect). IIRC,
localization treats magics of different flavors *differently* (but
IIRC, all of them do not lose their "magicness"). Moreover, IIRC,
magic handler can install a callback for the moments of
localization/delocalization; in principle this callback might
disable-enable magicality.
Hope this helps,
Ilya
I didn't claim that values weren't changed ; in fact, values are
changed, and 'set' magic is invoked (when it exists). I meant that
local() doesn't add or removes magic from the localized variable (except
when you localize the whole glob, via C<local *foo> : in this case a
whole new variable is created.)
I wasn't aware that localization was treating different types of magic
differently ; at least until next week, when I changed the way
localization of scalar works, to carry on the READONLY flag of localized
magic scalars whose magic can't handle "set" method. This was precisely
done to make code like this croak :
for ($1) { local $_ = 2 ; print }
However, some of the magic 'set' handlers modify their behavior
when localization or delocalization is occurring.
> Moreover, IIRC,
> magic handler can install a callback for the moments of
> localization/delocalization; in principle this callback might
> disable-enable magicality.
I can't find which callback you're referring to ; is it the 'set'
handler itself ?
--
Every time the wheel is reinvented it turns slower. -- JD in comp.editors
It's not so silly. I was bitten by this exact problem a few months
ago. I reported it as a bug, and was inexplicably told that it was
not a bug.
There's an interesting disease that technical people sometimes have.
The disease occurs when the sufferers have become so invested in the
particular rules and implementation details of their system that they
lose sight of what the system was supposed to be for and judge its
value only on the basis of its own self-consistency.
Perl culture likes to ridicule other programming language communities
for this disease. Among other things, it's the disease of CS
professors who invent beautifully orthogonal languages in which there
is one and only one way to say anything, but you can't actually get
any real work done. But hey, the implementation is perfectly clean
and theoretically beautiful, so who cares?
We have this disease in the Perl world, too. This is the disease that
causes people to say that the bahvior of this program is a feature,
not a bug:
@a = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
print length(@a);
It is a similar disease that led people to say that it was a feature
and not a bug that 'local $_' calls STORE when $_ happens to be
aliased to a tied variable. In some theoretical sense I suppose it is
perfectly reasonable. From a usability point of view, it is idiotic.
I think this was the most disappointing response I've gotten from p5p
in the past twelve months. The really amazing thing is that almost
everyone agrees that there are serious issues surrounding the
combination of local and tied variables, and that nobody seems to be
sure what the right behavior should be.
The bug causes action-at-a-distance of the worst kind, violates all
normal expectations of the effects of 'local', and it means that all
the well-meaning advice that people get about using 'local $_' is no
good, including the dozen or so times this advice appears in the
manual.
To be safe, you have to say
local *_;
But of course you must do this *after* copying the function arguments
from @_, because after 'local *_', the arguments are no longer
available.
> I didn't claim that values weren't changed ; in fact, values are
> changed, and 'set' magic is invoked (when it exists). I meant that
> local() doesn't add or removes magic from the localized variable
And I said that this is not *necessarily* so (although I never saw
anybody implementing this); since C handlers for the magic methods
know when they are called do to local()ization, they could have
added/removed magic.
The whole magicness support in Perl is absolutely broken (or was
absolutely broken the last time I tried to fix it). I have a halfway
fixed version somewhere on my harddisk, but I never had time to finish
it. [And most of the time I made some fixes, it was a very hard time
to pass them through p5p - I do not think many of fixes were included
at the end...]
Hope this helps,
Ilya
You mean you never need an approximation of log_10? :-p
--
Gaal Yahas <ga...@forum2.org>
http://gaal.livejournal.com/
Funny to see somebody pretending (?) that orthogonality complicates
"real work done". Try to do some "real work" with Perl; you can't.
Absense of orthogonality in Perl makes is very useful for one-liners.
One-liners form a very special culture. If a one-liner "does not
work", you just try to do it differently. However, if you want to be
sure what your Perl code is going what you want it to do, you need to
*run it*. This is not acceptable for programming any more-or-less
critical task. Programming in Perl allows a significant decrease in a
number of bugs; however, the bugs which remain in "written by experts"
Perl programs turn out to be of very-hard-to-recognize quality: things
which Perl does in a very non-intuitive way due to non-orthogonality.
> @a = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
> print length(@a);
I do not consider this as a bug or a gotcha. Missing warning - maybe.
However, if one removes orthogonality at this place, code maintance
will become much more complicated.
Myself, I found that I can't *predict* what a particular piece of Perl
is going to do with any reasonable degree of reliability. Even if I
restrict myself to a very small subset of Perl, things go out of hand
very often. And I never saw anybody who would be much better than me
in this task... It is always a horror story when I read somebody
else's code - or mine written some time ago. So much of code will not
do what people expect - or if they do, they will do it in simplest
cases only.
When I program in C, it is a pain to translate my train of thought to
code. Bugs happen - some stupid, some due to a bad algorithm. In
Perl, the translation to code stage is much more rewarding; as a
result, the bugs of two types mentioned above are significantly more
rare. However, being never sure what Perl interpreter will do with
the code I wrote compensates this warm and fuzzy feeling a lot. Bugs
happen - and IMO most of them are due to lack of orthogonality.
> It is a similar disease that led people to say that it was a feature
> and not a bug that 'local $_' calls STORE when $_ happens to be
> aliased to a tied variable. In some theoretical sense I suppose it is
> perfectly reasonable. From a usability point of view, it is idiotic.
Could not agree less. Probably we use local() for different tasks. I
call local() when I want localization of value. I would guess that
you call local() to work around other bugs/problems of Perl.
Let me also note my other gripe: most of the problems in this thread
would go away if people would not advertise using
for ($variable) {BLOCK}
construction as a programming idiom. IMO, this is a fantastic misuse
of Perl's (mis)features.
Hope this helps,
Ilya
Yes, it's an horror story for me as well when I read the code you
wrote some time ago ;-)
>> It is a similar disease that led people to say that it was a feature
>> and not a bug that 'local $_' calls STORE when $_ happens to be
>> aliased to a tied variable. In some theoretical sense I suppose it is
>> perfectly reasonable. From a usability point of view, it is idiotic.
>
>Could not agree less. Probably we use local() for different tasks. I
>call local() when I want localization of value. I would guess that
>you call local() to work around other bugs/problems of Perl.
I tend to agree with Ilya here. (On the other hand, I'm one of those
technical people who have the nose stuck right in the perl guts. And
I've a sinister backlog of "this is not a bug, this is a feature"-type
replies.)
Having thought about this particular problem, I came up with some kind
of user-level explanation :
* local $x, local @x, local %x localize the value of the corresponding
variable. That's similar to the constructs local $h{$k} and other
local(LVALUEHERE). (Note that I think that more local(LVALUE)
constructs could be permitted by perl.)
* local *gv localize the whole glob, creating a new variable. Hence
the workaround found by Mark-Jason to his problem : local *_.
However this has the unfortunate side-effect of emptying @_. I don't
consider this as a fundamental language design flaw, but as a example
of the poorly-chosen overloading of the *_ symbol, both for argument
lists and default scalar.
I think this should be documented more clearly somewhere, probably in
perlsub.
>Let me also note my other gripe: most of the problems in this thread
>would go away if people would not advertise using
>
> for ($variable) {BLOCK}
>
>construction as a programming idiom. IMO, this is a fantastic misuse
>of Perl's (mis)features.
FWIW the (short) programming guidelines I wrote for perl programmers
where I work forbid using foreach without an explicit loop variable.
--
Unfortunate is not *NIX
>>I think the bigger problem is the way 'local' works - by
>>assignment.
>
>local() works by undef()ing, not by assignment.
Right. But even then it uses assignment at the end of the block,
surely?
Is it correct to say that
{
local $v;
X;
}
is equivalent to
{
my $old_v = $v; # fresh symbol 'old_v'
undef $v;
X;
$v = $old_v;
}
What about 'local $v = 55'? Does that first undef and then assign?
>>Better, I think, would be to rebind the variable name to a new value
>
>"new value" has so many meanings that I'm at loss trying to guess
>what you want *exactly*.
I mean that
{
better_local $v;
X;
}
should be equivalent to
{
for $v (undef) {
X;
}
}
and that
{
better_local $v = 'foo';
X;
}
should mean the same as
{
for $v ('foo') {
X;
}
}
>>Not that assignment isn't sometimes useful. You might have a global
>>$debug_level which is in fact a tied scalar and does magic things
>>when assigned to. In that case 'local $debug_level = 1' does the
>>right thing. But this is pretty rare compared to the cases when
>>you'd prefer to ignore whatever scalar the variable was previously
>>bound to.
>
>Again, I'm at loss whether you for or against your proposal. ;-)
What I mean is that sometimes, in some rare cases, the current
behaviour of 'local' is perfect. But those are outweighed by the
cases where it's a gotcha.
>>I'd say there could be a warning when you alias a non-lexical
>>variable to something magical. If it's not magical then it should
>>be safe to localize.
>
>Then one should do the same for `while(<>)' stuff - if $_ is magical,
>a warning should be issued...
I agree.
>>Maybe you could take it a step further and warn only if you do the
>>aliasing and then go on to localize the aliased variable, or make a
>>subroutine call (it being assumed that the subroutine should be able
>>to say 'local $_' with confidence).
>
>Here the situation may quickly get out of reach in the sense of
>difficulty of detection such a situation.
I don't think so - it is fairly easy to statically detect whether a
BLOCK contains 'local $v' or any subroutine calls (or eval()). (Maybe
quite a few lines of C code, but essentially not difficult.)
--
Ed Avis <e...@membled.com>
>If you want a new variable, localize the glob :
> local *_; $_ = 'goodbye';
Aha! This is it, I think. Instead of 'local $_' I will try to write
'local *_' in my programs from now on.
>Yes. local() doesn't create a whole new variable. Magic is not
>touched by local() (and that's considered to be a feature, because
>it's useful for a bunch of special variables like %ENV, $/, etc.)
Yes, this is often useful. But one encouraged use of local, namely
sub foo {
local $_;
...
}
seems to be a false idiom. Tutorials warn that you should be wary of
using unlocalized $_. But in fact what you should do is not localize
$_ itself but the *_ typeglob.
Does that sound right?
--
Ed Avis <e...@membled.com>
>There's an interesting disease that technical people sometimes have.
>The disease occurs when the sufferers have become so invested in the
>particular rules and implementation details of their system that they
>lose sight of what the system was supposed to be for and judge its
>value only on the basis of its own self-consistency.
But Perl is defined by its implementation. Therefore any bug report
about perl's behaviour is automatically invalid!
>It is a similar disease that led people to say that it was a feature
>and not a bug that 'local $_' calls STORE when $_ happens to be
>aliased to a tied variable. In some theoretical sense I suppose it
>is perfectly reasonable. From a usability point of view, it is
>idiotic.
I think the problem is that 'local' has been promoted as something it
is not, and 'local $_' particularly so. Of course we all know that
the name is unfortunate too :-(.
>I think this was the most disappointing response I've gotten from p5p
>in the past twelve months. The really amazing thing is that almost
>everyone agrees that there are serious issues surrounding the
>combination of local and tied variables, and that nobody seems to be
>sure what the right behavior should be.
The right behaviour is whatever perl5 currently does, silly!
>To be safe, you have to say
>
> local *_;
>
>But of course you must do this *after* copying the function arguments
>from @_, because after 'local *_', the arguments are no longer
>available.
Blech.
--
Ed Avis <e...@membled.com>
>FWIW the (short) programming guidelines I wrote for perl programmers
>where I work forbid using foreach without an explicit loop variable.
Seriously? Not even for
print "got string $_\n" foreach @strings;
Really, if you want Python, you know where to find it.
--
Ed Avis <e...@membled.com>
Yes, seriously; the guideline is in fact "when you can avoid fiddling
with $_, do it". Mainly because I've seen to many functions that modify
$_ without restoring it.
>Really, if you want Python, you know where to find it.
Or I use map in void context :-p
--
Unassailable is not *NIX
What about:
local *_ = \@_;
to keep only the args in place?
--
--------- Gordon Lack --------------- gml...@ggr.co.uk ------------
This message *may* reflect my personal opinion. It is *not* intended
to reflect those of my employer, or anyone else.
Doesn't work. Don't know why. You can say:
my $args = \@_; local *_; *_=$args;
Either has the side effect of refcounting the parameters.
Right. (Modulo the fact that some magic values catch SAVE/RESTORE and
do something special during this time...)
> What about 'local $v = 55'? Does that first undef and then assign?
My impression is that it does.
> {
> better_local $v;
> X;
> }
>
> should be equivalent to
>
> {
> for $v (undef) {
> X;
> }
> }
Is not this what our() is for? Or do you want visibility in
subroutines too? Then is it the same as
my $v_new;
local *v = *v;
*v = \$v_new;
?
Essentially, give a temporary value to *v{SCALAR}... Easy to
implement in XS. Hmm, I wonder whether my additions to Scalar::Utils
(or what was the name ;-) of a year or two ago made it; these
additions allowed something like
LEAVE {code to execute at the end of the current block};
Modifying this code slightly, one could easily implement
local_scalar *v;
with the semantic you want.
> What I mean is that sometimes, in some rare cases, the current
> behaviour of 'local' is perfect. But those are outweighed by the
> cases where it's a gotcha.
See my other posting. These usages which "outweight" perfect ones are
due to failing attempts to fix *other* problems of Perl. When local()
is used *as designed*, to give a temporary new value, it behaves as it
should.
> >Here the situation may quickly get out of reach in the sense of
> >difficulty of detection such a situation.
>
> I don't think so - it is fairly easy to statically detect whether a
> BLOCK contains 'local $v' or any subroutine calls (or eval()). (Maybe
> quite a few lines of C code, but essentially not difficult.)
Only if it is
local $v;
and not
local ${whatever()};
Even if you want to support the first case only, then it may still be
too much work for a *warning* (i.e., "do nothing").
Yours,
Ilya
>>>FWIW the (short) programming guidelines I wrote for perl programmers
>>>where I work forbid using foreach without an explicit loop variable.
>the guideline is in fact "when you can avoid fiddling with $_, do
>it". Mainly because I've seen to many functions that modify $_
>without restoring it.
Surely then the coding standards should say 'do not modify the
caller's $_ in a subroutine'. You wouldn't avoid use of stdout on the
grounds that some routine might open it to a different file and not
restore it.
The answer is to fix the broken code, not work around it. At least,
that is the Right Thing that you'd expect coding standards to promote.
--
Ed Avis <e...@membled.com>
> Yes, seriously; the guideline is in fact "when you can avoid fiddling
> with $_, do it". Mainly because I've seen to many functions that modify
> $_ without restoring it.
>
> >Really, if you want Python, you know where to find it.
>
> Or I use map in void context :-p
Again, I find this insistence on a "proper" use of map() incredibly
misplaced. It would take just a few minutes to make map() behave
properly in void context (if it does not yet). How much time people
spend on "educating" other people - instead of fixing this bug?
Yours,
Ilya
[Which is "good"; the only drawback (and *the* reason for current
behaviour) is a slowdown - but this code is going to be slow anyway.]
What happens is that @_ - which is a "fake" array (whatever this means
:-[) is promoted to a real one - probably during \@_. However, local
*_ was executed first - and it may be that its result is the "old" @_.
Then the assignment
result_of(local @_) <<=== result_of(\@_)
is executed - which may modify "the wrong" array. [It was just a
random musing; imagining how a bug may be "implemented" is useful, but
not very often productive.] [It does not help that this assignment is
also "fake". ;-]
Thanks for the analysis,
Ilya
From Jarkko's 5.8.1 announcement:
C<map> in void context is no longer expensive. C<map> is now context
aware, and will not construct a list if called in void context.
Steffen
--
@n=([283488072,6076],[2105905181,8583184],[1823729722,9282996],[281232,
1312416],[1823790605,791604],[2104676663,884944]);$b=6;@c=' -/\_|'=~/./g
;for(@n){for$n(@$_){map{$h=int$n/$b**$_;$n-=$b**$_*$h;$c[@c]=$h}reverse
0..11;push@p,map{$c[$_]}@c[reverse$b..$#c];$#c=$b-1}$p[@p]="\n"}print@p;
This bug is fixed in 5.8.1. Tassilo von Parseval provided the one-line
patch, and guess who applied it ? (change #21062.)
>> What about:
>>
>> local *_ = \@_;
>>
>>to keep only the args in place?
>
>
> Doesn't work. Don't know why.
Seems to work for me (though I coudl well just be using cases where
it happens to work). It seems to work in the example given earlier
inteh thread using tied variables (4 storing -> 1 storing).
and:
==========
#!/usr/bin/perl
%_ = qw( a 1 b 2 c 3);
$_ = "Global";
print 'orig $_ is: ', $_, "\n";
print 'orig %_ keys are: ', join(', ', keys %_), "\n";
sub mysub {
print "orig args: ", join(', ', @_), "\n";
local *_ = \@_;
print "new args: ", join(', ', @_), "\n";
print 'new $_ is: ', $_, "\n";
print 'new %_ keys are: ', join(', ', keys %_), "\n";
}
for (my $val = 3) {
mysub(1, 2, 3);
print 'loop $_ is: ', $_, "\n";
}
print 'final $_ is: ', $_, "\n";
==========
produces:
orig $_ is: Global
orig %_ keys are: a, b, c
orig args: 1, 2, 3
new args: 1, 2, 3
new $_ is:
new %_ keys are:
loop $_ is: 3
final $_ is: Global
--
-*- Just because I've written it here doesn't -*-
-*- mean that you should, or I do, believe it. -*-
$ perl -we'sub foo { local *_ = \@_; $_ = "x" } foo for "y"'
Modification of a read-only value attempted at -e line 1.
Fails under 5.8.0, 5.8.1, and a fairly old bleadperl@21299.
>> {
>> better_local $v;
>> X;
>> }
>>
>>should be equivalent to
>>
>> {
>> for $v (undef) {
>> X;
>> }
>> }
>
>Is not this what our() is for?
I don't think so... according to perlfunc:
>The "our" declaration has no semantic effect unless "use strict vars"
>is in effect, in which case it lets you use the declared global
>variable without qualifying it with a package name.
whereas the above would not affect any global $v.
>Or do you want visibility in subroutines too?
I'm not that bothered; if thinking up a 'better local' then you would
want that but my main concern is not affecting or being affected by
the caller.
>Then is it the same as
>
> my $v_new;
> local *v = *v;
> *v = \$v_new;
Possibly, except that assigning to *v affects $v, @v, %v etc. and I'd
want to only 'localize' one at a time.
But yes, others did suggest localizing *_. Apart from affecting @_ as
well as $_, this is what I want.
>When local() is used *as designed*, to give a temporary new value, it
>behaves as it should.
That's a normative statement and so hard to disagree with. All I can
say is that if so, local is misrepresented and promoted as being
something it isn't - and that Perl lacks a primitive for what most of
the time is really wanted, a way to insulate $_ (or other global) from
the caller and to insulate the caller from this block.
>>it is fairly easy to statically detect whether a
>>BLOCK contains 'local $v' or any subroutine calls (or eval()).
>Only if it is
> local $v;
>and not
> local ${whatever()};
Is that legal? For me it gives 'can't localize through a reference'.
>Even if you want to support the first case only, then it may still be
>too much work for a *warning* (i.e., "do nothing").
I hope it would be a compile-time check, like 'use strict', and so
wouldn't significantly slow down programs; the cost would be in the
extra code.
--
Ed Avis <e...@membled.com>
Well, I never *want* "to insulate" things. Sometimes I'm *forced* to
do so - due to Perl (mis)features. So I see no need to "promote" this
usage.
In short: Perl is very much broken; IMO, the *root* of the problem(s)
discussed in this thread is in different place than one you point to.
There "should" be no need to "insulate" things; thus one "should" use
local() as a syringe, not as a condom.
Of course, with Perl as it stands, one may want the safe-sex device
too. But do not destroy the syringe, please.
> >Only if it is
> > local $v;
> >and not
> > local ${whatever()};
>
> Is that legal? For me it gives 'can't localize through a reference'.
Symbolic references should be legal. Checking... Nope! Strange...
> >Even if you want to support the first case only, then it may still be
> >too much work for a *warning* (i.e., "do nothing").
>
> I hope it would be a compile-time check, like 'use strict', and so
> wouldn't significantly slow down programs; the cost would be in the
> extra code.
I meant the cost in the programmer's time: time to implemenent this
(rather involved) check.
Thanks,
Ilya
>>>When local() is used *as designed*, to give a temporary new value, it
>>>behaves as it should.
>>Perl lacks a primitive for what most of the time is really wanted, a
>>way to insulate $_ (or other global) from the caller and to insulate
>>the caller from this block.
>
>Well, I never *want* "to insulate" things. Sometimes I'm *forced* to
>do so - due to Perl (mis)features.
Er... okay.
Surely you agree that with perl5 as it stands a programmer often needs
to use $_ in a subroutine without being affected by the caller's
value?
>In short: Perl is very much broken; IMO, the *root* of the problem(s)
>discussed in this thread is in different place than one you point to.
The root of the problem, I think, is that $_ is a global variable
rather than a lexical. I believe this is fixed in Perl 6.
BTW - I'm not advocating the removal of 'local' from the language,
only the addition (or discovery) of some other mechanism which really
does make a block of code unaffected by whatever the previous value of
some global was, and makes the code executed after that block returns
unaffected by whatever the block did with the global.
--
Ed Avis <e...@membled.com>
> Surely you agree that with perl5 as it stands a programmer often needs
> to use $_ in a subroutine without being affected by the caller's
> value?
Your "needs", is it related only to
my $in;
while (defined ($foo = <IN>)) vs while (<IN>)
or do you have some other example of a "need to use $_"? Somehow I
could not remember anything else...
> >In short: Perl is very much broken; IMO, the *root* of the problem(s)
> >discussed in this thread is in different place than one you point to.
>
> The root of the problem, I think, is that $_ is a global variable
> rather than a lexical. I believe this is fixed in Perl 6.
I think that the root is different: that $_ is too special. It is
nice that it can be omited in one-liners; however, I do not think that
the fact that one can omit it benefits larger programs.
[Btw, can one do `my $_;' transparently in 5.8.1? So that the Perl
buildins start to work on the lexical $_ when it is in scope?]
> BTW - I'm not advocating the removal of 'local' from the language,
> only the addition (or discovery) of some other mechanism which really
> does make a block of code unaffected by whatever the previous value of
> some global was, and makes the code executed after that block returns
> unaffected by whatever the block did with the global.
I'm confused - do not you mean `my' here? It looks like you do not
want to "inject" new value into this global, just make it invisible...
Yours,
Ilya
> $ perl -we'sub foo { local *_ = \@_; $_ = "x" } foo for "y"'
> Modification of a read-only value attempted at -e line 1.
>
> Fails under 5.8.0, 5.8.1, and a fairly old bleadperl@21299.
Thanks for the example. Must be a change in 5.8 then, as 5.6.1 does
not produce this error (and does work).
perl5.6.1 -lwe'sub foo { local *_ = \@_; $_ = "x"; print } for ("y")
{foo;print}'
x
y
>> Surely you agree that with perl5 as it stands a programmer often needs
>> to use $_ in a subroutine without being affected by the caller's
>> value?
>
>Your "needs", is it related only to
>
> my $in;
> while (defined ($foo = <IN>)) vs while (<IN>)
>
>or do you have some other example of a "need to use $_"?
The while-diamond loop is one example; apart from that you sometimes
want to assign to $_ directly. I don't do that so often, usually I
use for-aliasing, but a lot of code does say
local $_ = 'fafa';
...
and I think it's reasonable that this should work without breaking for
certain previous values of $_. Okay, okay, it does work according to
the 'intended meaning' of 'local', but then almost any Perl program
works correctly according to the intended meaning of Perl, which is
defined by the current implementation modulo acknowledged bugs. I
mean it ought to work using some new construct that could be a better
replacement for 'local' in code like the above.
>>The root of the problem, I think, is that $_ is a global variable
>>rather than a lexical. I believe this is fixed in Perl 6.
>
>I think that the root is different: that $_ is too special.
The same problem would affect any global variable which is then
localized; it happens that $_ is the most commonly used global.
>It is nice that it can be omited in one-liners; however, I do not
>think that the fact that one can omit it benefits larger programs.
I don't agree, given that a well-written large program will usually be
broken up into small, relatively self-contained routines. I don't see
anything wrong in saying 'foreach (red green blue) { ... }' as part of
a simple five-line function, even if that function is part of a 50kloc
project. But I wouldn't want to do the same over a large and complex
loop. As with most style matters, it's a question of judging each
individual case.
>>BTW - I'm not advocating the removal of 'local' from the language,
>>only the addition (or discovery) of some other mechanism which
>>really does make a block of code unaffected by whatever the previous
>>value of some global was, and makes the code executed after that
>>block returns unaffected by whatever the block did with the global.
>
>I'm confused - do not you mean `my' here?
No, because 'my' creates a new lexical variable and (consequently?)
would not work with $_.
>It looks like you do not want to "inject" new value into this global,
>just make it invisible...
Right, there are two choices based on lexical or dynamic scoping.
One might simply hide the global variable inside its syntactic block:
our $x = 5;
sub foo { hide_global $x = 4; print "foo(): $x\n"; bar() }
sub bar { print "bar(): $x\n" }
foo();
print "$x\n";
% ./test
foo(): 4
bar(): 5
5
The other choice would be more like 'local', switching the global for
a fresh scalar with the same name for the runtime duration of a block
of code. s/hide_global/fancy_local/ in the above, and:
% ./test
foo(): 4
bar(): 4
5
Much of the time, this would give the same results as the current
'local' but it would work differently when the global's previous value
was something magic, which couldn't be straightforwardly undeffed and
then assigned a new value. Rather than STORE on the existing scalar,
the global variable name would be bound to a new scalar for the
runtime duration of the block.
I'd be happy with either of these, although 'hide_global' is a little
odd in that it makes a lexical variable with the same name as a global
one - you could rebind $_ using this. 'fancy_local' is better I
think, it's an idea of what local should have been if done properly.
More some value of 'properly' which I admit is based on personal
expectations and a vague feeling about what most programmers would
consider surprising behaviour. Of course the existing 'local' could
still exist for cases where its semantics are more appropriate - and
where the outside value of the global is a non-magic scalar, the
meanings of 'local' and 'fancy_local' would effectively be the same.
--
Ed Avis <e...@membled.com>
> The while-diamond loop is one example; apart from that you sometimes
> want to assign to $_ directly.
What for? To save 3 keyspresses (and possibly get into a lot of
trouble), or something deeper?
> >I think that the root is different: that $_ is too special.
>
> The same problem would affect any global variable which is then
> localized; it happens that $_ is the most commonly used global.
Can you list such globals - which one wants to localize *without* the
semantic of "injecting new value"?
> >It is nice that it can be omited in one-liners; however, I do not
> >think that the fact that one can omit it benefits larger programs.
> I don't agree, given that a well-written large program will usually be
> broken up into small, relatively self-contained routines.
If you want to do this, use something else than Perl. In my
experience, most large Perl programs work due to coincidences only.
You cannot make things "relatively self-contained" with the current
state of diagonality - there are too many unexpected side effects.
[Of course, one can argue about how relative is your "relatively". ;-]
> I don't see anything wrong in saying 'foreach (red green blue) {
> ... }' as part of a simple five-line function, even if that function
> is part of a 50kloc project.
You see: you use a construct with *enormous* side effects, and claim
that it is save to use in 50kloc project. How are you going to debug
things if this function calls some other function (e.g, via tie() or
overloading), and this other function happens to set $_?
> >>BTW - I'm not advocating the removal of 'local' from the language,
> >>only the addition (or discovery) of some other mechanism which
> >>really does make a block of code unaffected by whatever the previous
> >>value of some global was, and makes the code executed after that
> >>block returns unaffected by whatever the block did with the global.
> >
> >I'm confused - do not you mean `my' here?
>
> No, because 'my' creates a new lexical variable and (consequently?)
> would not work with $_.
But you advocate a change to the language anyway. Why not make `my
$_' do what people expect?
Yours,
Ilya
>>>or do you have some other example of a "need to use $_"?
>
>>The while-diamond loop is one example; apart from that you sometimes
>>want to assign to $_ directly.
>
>What for?
Well, the reasons you'd expect - to store a value in $_.
$_ = <FILE>;
/z/ && print "read a line containing 'z'\n";
>To save 3 keyspresses (and possibly get into a lot of trouble),
I think this is getting towards a circular argument. My point is that
it should be possible to assign to $_ without getting into trouble.
That doesn't sound too much to ask, especially since the code doesn't
give any indication that something dangerous is happening.
>>>I think that the root is different: that $_ is too special.
>>
>>The same problem would affect any global variable which is then
>>localized; it happens that $_ is the most commonly used global.
>
>Can you list such globals - which one wants to localize *without* the
>semantic of "injecting new value"?
Actually I'd ask which variables should get the special treatment of
keeping the existing scalar and calling STORE on it. Surely most of
the time you really don't care what the previous value of some global
was, and don't want to be affected by it at all. All that matters is
restoring the status quo when your block exits.
I'd say that the only variables one wants to localize while keeping
magic are the builtin magic variables like $/. 'local $/' is a good
idiom. 'local $_' probably is not.
>>>It is nice that it can be omited in one-liners; however, I do not
>>>think that the fact that one can omit it benefits larger programs.
>
>>I don't agree, given that a well-written large program will usually be
>>broken up into small, relatively self-contained routines.
>
>If you want to do this, use something else than Perl. In my
>experience, most large Perl programs work due to coincidences only.
>You cannot make things "relatively self-contained" with the current
>state of diagonality - there are too many unexpected side effects.
I tend to agree, but I thought we were discussing some way to improve
the situation. Are you arguing that Perl 5 is so irredeemably broken
that it's not worth trying to change or extend the language to make
modular programs easier to write?
>>I don't see anything wrong in saying 'foreach (red green blue) {
>>... }' as part of a simple five-line function, even if that function
>>is part of a 50kloc project.
>
>You see: you use a construct with *enormous* side effects, and claim
>that it is save to use in 50kloc project.
Like I say, I'm trying to work out conditions under which such
constructs are safe to use.
>How are you going to debug things if this function calls some other
>function (e.g, via tie() or overloading), and this other function
>happens to set $_?
How are you going to debug things if some other module has set up a
source code filter which turns 'foreach' into 'unlink'? There is a
limit to what you can worry about.
However, you have a valid concern because it's very easy to set $_,
accidentally or otherwise. The 'while (<>)' construct is probably the
worst example of hidden side-effects on $_. In this case I would
simply require that functions document any side effects they have;
this is just normal practice. It would also be hard to debug if some
other function did 'kill 9, $$' - to avoid the problem one doesn't
write functions that do that, or at least one documents them.
>>>>BTW - I'm not advocating the removal of 'local' from the language,
>>>>only the addition (or discovery) of some other mechanism which
>>>>really does make a block of code unaffected by whatever the
>>>>previous value of some global was,
>>No, because 'my' creates a new lexical variable and (consequently?)
>>would not work with $_.
>
>But you advocate a change to the language anyway. Why not make `my
>$_' do what people expect?
I dunno, it depends what people expect. My expectation would be for
'my $_' to be some kind of error since 'my' declares lexical variables
and $_ is a global, as every perl5 programmer should know. Also 'my'
has connotations of lexical scope, not dynamic scope. Consider
# Alters the string in $_.
sub trim() { s/^\s+//; s/\s+$// }
{
something $_; # local, or my, or what?
$_ = <FILE>;
trim();
tr/abc/def/;
s/fred/jim/;
print;
}
'my $_' would not make the new value available to the called subroutine.
--
Ed Avis <e...@membled.com>
I repeat my question:
> >To save 3 keyspresses (and possibly get into a lot of trouble)?
Or do you know a case when assignment to $_ has *more* benefits?
> I think this is getting towards a circular argument. My point is that
> it should be possible to assign to $_ without getting into trouble.
Just use *_ = \${'!!!'} at the top of your program, and all the
magical features of $_ disappear (at least I think so; maybe one needs
to assign to $::{_} instead). Then assign to it as often as you want.
I repeat my point: having $_ with a special semantic is very good for
one-liners. It is very bad for anything significantly larger than
this.
> I'd say that the only variables one wants to localize while keeping
> magic are the builtin magic variables like $/.
This is another piece of serious misdesign of Perl: instead of having
special functions to configure Perl state, the state is kept in
zillions of special variables. Just look at $^H, for god sake!
> I tend to agree, but I thought we were discussing some way to improve
> the situation. Are you arguing that Perl 5 is so irredeemably broken
> that it's not worth trying to change or extend the language to make
> modular programs easier to write?
Of course it is possible (and not that hard) to improve things. At
least *technically* possible. E.g., I do not think that many of my
patches directed at making things better on large scale made it
through p5p. (One notable exception is 3-argument open()...)
And I do not think the situation will improve - until more people drop
this "we have a wonderful language!" nonsense. Yes, for a lot of
people (including myself), Perl is much better than alternatives in
transmuting from train of thought to programs. But this is microeconomics.
In any reasonably large project it is an interaction of many different
trains of thoughts which matters; and in this department Perl is much
weakier than in the others. Yes, people get emotionally attached to
languages; but when these emotions stop people from getting a fair
assessment of the defiencies of the language, this makes it much
harder to improve the things.
My assessment is: diagonality (or at least the particular
implementation of diagonality we see in Perl 5) creates *gaping* holes
in "Perl as a language of programming at large". The only way to fix
it while preserving backward compatibility is introduction of new
pragmas which switch off all/some quirks.
E.g.,
my $_;
may be a kind of such a pragma - all operations which were acting on
$_ start to act on (my $_).
> >>I don't see anything wrong in saying 'foreach (red green blue) {
> >>... }' as part of a simple five-line function, even if that function
> >>is part of a 50kloc project.
> >
> >You see: you use a construct with *enormous* side effects, and claim
> >that it is save to use in 50kloc project.
>
> Like I say, I'm trying to work out conditions under which such
> constructs are safe to use.
The answer is easy: none. In presense of tie()d values, CORE::GLOBAL,
and operator overloading, there is no useful construct which can't
call a random buggy subroutine.
> >How are you going to debug things if this function calls some other
> >function (e.g, via tie() or overloading), and this other function
> >happens to set $_?
>
> How are you going to debug things if some other module has set up a
> source code filter which turns 'foreach' into 'unlink'? There is a
> limit to what you can worry about.
When was the last time you saw such a filter? Now guess, when was the
last time I was looking for who is changing my array which should have
been constant? Right, yesterday. (BTW, the culprit is MakeMaker.)
> However, you have a valid concern because it's very easy to set $_,
> accidentally or otherwise. The 'while (<>)' construct is probably the
> worst example of hidden side-effects on $_. In this case I would
> simply require that functions document any side effects they have;
Com'on. It is much easier to force people to write good code than to
right good documentation.
> this is just normal practice. It would also be hard to debug if some
> other function did 'kill 9, $$' - to avoid the problem one doesn't
> write functions that do that, or at least one documents them.
When I write kill 9, $$, I most probably understand well the side
effects of this function call. Likewise if I install a source filter
for my use()r. However, the side effects due to making things easier
in "one-liners" are much subtler; nobody can be expected to keep in
mind *all* of them.
How many peole can describe how many elements split /$re/, $a returns
for all possible values of $re and $a? Recently I discovered that I
can't: there is yet another special case I did not know about (though
I spent innumerable amount of time cleaning up split()).
> >But you advocate a change to the language anyway. Why not make `my
> >$_' do what people expect?
>
> I dunno, it depends what people expect. My expectation would be for
> 'my $_' to be some kind of error since 'my' declares lexical variables
> and $_ is a global, as every perl5 programmer should know.
Eh? $x is a global too - until you do my $x...
> Also 'my'
> has connotations of lexical scope, not dynamic scope. Consider
>
> # Alters the string in $_.
> sub trim() { s/^\s+//; s/\s+$// }
>
> {
> something $_; # local, or my, or what?
> $_ = <FILE>;
> trim();
> tr/abc/def/;
> s/fred/jim/;
> print;
> }
>
> 'my $_' would not make the new value available to the called subroutine.
This is exactly the point. In the scope of `my $_' the variable $_
is, well, lexical. So you code trim() to take an argument - as it
should if this is not a throw-away piece of code.
Hope this helps,
Ilya
Yes ; C<local *_> effectively localizes $_ *and* removes all magic from
it. Drawback : it empties @_ as well.
> This is another piece of serious misdesign of Perl: instead of having
> special functions to configure Perl state, the state is kept in
> zillions of special variables. Just look at $^H, for god sake!
$^H and its evil twin %^H are not meant to be user visible, completely
broken and likely to be replaced by something more sensible.
> My assessment is: diagonality (or at least the particular
> implementation of diagonality we see in Perl 5) creates *gaping* holes
> in "Perl as a language of programming at large". The only way to fix
> it while preserving backward compatibility is introduction of new
> pragmas which switch off all/some quirks.
>
> E.g.,
>
> my $_;
>
> may be a kind of such a pragma - all operations which were acting on
> $_ start to act on (my $_).
Interesting ; that could be done, first by removing the compile-time
check that prevents from doing 'my $_', then by adding a new lexical
hint meaning "we're in a scope where $_ is lexicalized", then by
modifying the code that adds access to $_ to parameterless special
functions to check for this hint, to lookup $_ in the current pad
instead.
(Currently "print" is internally compiled as something equivalent to
"print $main::_" : $_ is always looked up in the symbol table.)
However that's One Of The Things That Must Wait For A Proper Lexical
Hint Mechanism.
(Hmm... I'll see about adding a note about "my $_" in perltodo.pod.)
>> # Alters the string in $_.
>> sub trim() { s/^\s+//; s/\s+$// }
>>
>> {
>> something $_; # local, or my, or what?
>> $_ = <FILE>;
>> trim();
>> tr/abc/def/;
>> s/fred/jim/;
>> print;
>> }
>>
>> 'my $_' would not make the new value available to the called subroutine.
>
> This is exactly the point. In the scope of `my $_' the variable $_
> is, well, lexical. So you code trim() to take an argument - as it
> should if this is not a throw-away piece of code.
That's how I understood it.
--
Every time the wheel is reinvented it turns slower... -- JD in comp.editors
>> $_ = <FILE>;
>> /z/ && print "read a line containing 'z'\n";
>
>I repeat my question:
>
>>>To save 3 keyspresses (and possibly get into a lot of trouble)?
To write code which is in a straightforwward, idiomatic style (as
often used in Perl documentation) and with an expectation it will work.
I don't understand what you are getting at. Suppose a user U posted
to this group complaining of a seeming bug in Perl and is answered by
some other poster P:
U: Whenever I use "hello $name" perl crashes. But 'hello ' . $name
works fine.
P: Why are you using string interpolation? It obviously causes
problems.
U: But I thought string interpolation would work. It should work.
P: Why are you using it? Just to save keystrokes?
I am sure this is not a fair representation of your argument but
that's how it seems to me. There must be some point I'm missing.
Assigning a value to $_, using regexp matching like /z/, and using
'local $_' are all straightforward bits of Perl code recommended in
the standard documentation. If they don't work or do surprising
things (and _really_ surprising things, not just the usual level of
DWIMmery) then something is broken. Either the documentation can be
fixed to add explicit warnings or perl can be changed or extended to
make such constructs safer.
But as I say below, I don't agree that there is anything special
about $_ that makes such code bad. I think the problem is just the
same with any global variable.
>Or do you know a case when assignment to $_ has *more* benefits?
As far as I can tell using $_ has few benefits beyond the syntactic.
Most $_ uses can be mechanically translated to an equivalent construct
using a named global variable. There are a few cases such as map()
and grep() where using $_ is required by the language, although there
too you can start off by assigning it to some other variable.
But stylistically it has some advantages; not only because of the
syntax (and I do think that 's/^\s+//; s/\s+$//' is clearer than the
same code written with explicit =~, though you may disagree) but also
for coding style. Sometimes for performance or just for convenience I
have written subroutines that modify a scalar in-place. This could be
done by passing in a reference but it seems more in in tune with the
language's builtins (s///, tr///) to modify $_.
You may argue that such styles should be avoided, but if so a change
to perl is still needed, to make them deprecated by the documentation
(and perhaps remove $_ from the language altogether). As it happens I
don't agree with such a diagnosis. I think the problem is not $_ but
'local'. Or if it is $_, then every global variable is equally
guilty.
>>I think this is getting towards a circular argument. My point is that
>>it should be possible to assign to $_ without getting into trouble.
>
>Just use *_ = \${'!!!'} at the top of your program, and all the
>magical features of $_ disappear
I don't think $_ has any magical features. As far as I can tell it is
just an ordinary global variable which can be used to store scalars.
The only difference from other global variables is in namespace
resolution - $_ is accessible from all namespaces.
I think that a program such as
for ('hello') {
/z/ && print "match\n";
print;
}
is directly equivalent to
{ package foo; our $xxx }
for $foo::xxx ('hello') {
$foo::xxx =~ /z/ && print "match\n";
print $foo::xxx;
}
The magic of $_ is purely syntactic. '/z/' is an abbreviation for
'$_ =~ /z/'. 'while (<FH>)' is an abbreviation for
'while (defined($_ = <FH>))'. If these constructs are dangerous then
anything using a non-lexical variable is dangerous.
But in Perl it should be safe to use non-lexical variables because we
have the 'local' keyword that gives a variable a new value inside a
block and restores its value when leaving the block. Unfortunately,
this isn't enough - which is what my original posting was about.
There are two answers: avoid using global variables entirely (and not
just $_, all of them, and package-scoped ones too) unless you are
happy for 'local' to do strange things when the old value was magic;
or find some better thing than 'local' that does what's needed to
truly give dynamic scoping.
>I repeat my point: having $_ with a special semantic is very good for
>one-liners. It is very bad for anything significantly larger than
>this.
I do not think $_ has special semantics. It has special syntax, that
is all. Exactly the same semantics apply to $foo::xxx as far as I can
tell.
>This is another piece of serious misdesign of Perl: instead of having
>special functions to configure Perl state, the state is kept in
>zillions of special variables.
Agreed. But as it happens $_ is not one of these, it does not store
internal state of Perl.
(Actually I wouldn't mind that much to have variables instead of
getters and setters for configuration data, but they'd need to be
arranged more tidily.)
>Of course it is possible (and not that hard) to improve things. At
>least *technically* possible. E.g., I do not think that many of my
>patches directed at making things better on large scale made it
>through p5p. (One notable exception is 3-argument open()...)
>
>And I do not think the situation will improve - until more people
>drop this "we have a wonderful language!" nonsense.
It's well known that this tends to happen with programming languages,
eg dmr: 'People involved with successful languages can become rabidly
conservative no matter what their general inclinations.'
(<http://www.gotw.ca/publications/c_family_interview.htm>). But
usually the language designer himself does not share this feeling.
(Python may be an exception to this rule...)
It does seem that Perl 6 addresses some of the problems which bug me
(in particular, it makes $_ a lexical not a global) and perhaps some
of your gripes too. But it's vapourware ATM.
>Yes, people get emotionally attached to languages; but when these
>emotions stop people from getting a fair assessment of the defiencies
>of the language, this makes it much harder to improve the things.
We agree on that. Partly because of 'Perl is wonderful' and partly
because the language is defined by its implementation, it's difficult
to persuade many that the language needs changing. They think the
status quo is good enough, or at least consistent and logical, and so
there is no need to change the language. But you seem to reach the
same conclusion from the opposite side: the language is irredeemably
broken in some places, that some constructs are inherently unsafe and
obviously not to be used in large programs, and so it is not worth
trying to fix things. There is, I hope, a tenable middle position
that the language is neither wholly perfect nor wholly broken, and
that some changes or additions are possible to make it work better.
When discussing language changes you have to think about what _should_
work, not just what does work now. Otherwise no bugfix would ever be
made. String interpolation might be known to crash the interpreter,
therefore no sane person would use it, therefore what is the point of
fixing it?
>The only way to fix it while preserving backward compatibility is
>introduction of new pragmas which switch off all/some quirks.
>
>E.g.,
>
> my $_;
>
>may be a kind of such a pragma - all operations which were acting on
>$_ start to act on (my $_).
Hmm, so 'while (<>)' for example would have an implicit lexically
scoped $_ inside the loop body.
That would be one answer, but I think I'd prefer to have dynamic
scoping available too - that is, the new value of $_ is available to
called subroutines because it depends on the runtime life of the block
not the location in source code of a line using $_. I just want this
to happen without bizarre side-effects when $_ previously contained a
magical scalar.
>>>>I don't see anything wrong in saying 'foreach (red green blue) {
>>>>... }' as part of a simple five-line function,
>>Like I say, I'm trying to work out conditions under which such
>>constructs are safe to use.
>
>The answer is easy: none. In presense of tie()d values,
>CORE::GLOBAL, and operator overloading, there is no useful construct
>which can't call a random buggy subroutine.
Then the conditions required are that other code doesn't do
gratuitously strange things. When programming in C, I make the
reasonable assumption that no included header file contains
'#define if potato'. Similarly in Perl I assume that nobody else's
code has overridden 'print' - unless I deliberately included a library
which is documented to do that.
I do not program in an environment where there are other bits of code
I must include which contrive to do the most bizarre things to mess up
my own code.
>Now guess, when was the last time I was looking for who is changing
>my array which should have been constant? Right, yesterday. (BTW,
>the culprit is MakeMaker.)
...except that when it comes to MakeMaker, all bets are off ;-P.
Still this is an exception. Most Perl libraries manage to do their
job without causing such odd side-effects, and just as there is an
unwritten contract that calling Date::Manip::ParseDate() will not
cause an infinite loop or chew up ten megabytes of memory, so there is
an unwritten contract that the routine won't go around redefining core
functions or changing the global @ARGV.
If you really are unprepared to give anyone else's code the benefit of
the doubt, you could use Java or some other language that is designed
to mix trusted and untrusted code.
>>However, you have a valid concern because it's very easy to set $_,
>>accidentally or otherwise. The 'while (<>)' construct is probably
>>the worst example of hidden side-effects on $_. In this case I
>>would simply require that functions document any side effects they
>>have;
>
>Com'on. It is much easier to force people to write good code than to
>right good documentation.
Probably true. In which case 'while (<>)' either needs to be
discommended in the Perl documentation, or changed to not affect the
outside value of $_. At the moment it is held up as idiomatic Perl
code but has not-so-obvious side effects (at least if inside some
called function).
>>this is just normal practice. It would also be hard to debug if some
>>other function did 'kill 9, $$' - to avoid the problem one doesn't
>>write functions that do that, or at least one documents them.
>
>When I write kill 9, $$, I most probably understand well the side
>effects of this function call. Likewise if I install a source filter
>for my use()r. However, the side effects due to making things easier
>in "one-liners" are much subtler; nobody can be expected to keep in
>mind *all* of them.
Yes. That is why I would like to get rid of strange side effects that
are not obvious. 'while (<>)' setting $_ outside the loop body is one
such strange side effect. However I don't think that some shortcuts
such as 'print' for 'print $_' have any odd behaviour.
>How many peole can describe how many elements split /$re/, $a returns
>for all possible values of $re and $a?
That is another area of the language which needs cleaning up. But
it's not quite the same as what's discussed above, since however
strange the behaviour of 'split' may be, at least it does not have
side effects of setting variables in some faraway and unrelated bit of
code. Well, apart from $1, $2 and the other regexp magic vars :-(.
>>>But you advocate a change to the language anyway. Why not make `my
>>>$_' do what people expect?
>>
>>I dunno, it depends what people expect. My expectation would be for
>>'my $_' to be some kind of error since 'my' declares lexical
>>variables and $_ is a global, as every perl5 programmer should know.
>
>Eh? $x is a global too - until you do my $x...
Yes, but seeing use of $_ in a program you expect it to be global. At
least I would. It would be too surprising to see code that uses $_
but doesn't get the global, dynamic-scoping behaviour. Maybe this is
just because I'm too used to the current way, and programmer
expectations would change once your proposed 'my $_' got into the
language. Programmers would have to change their feelings about $_
with perl6 anyway.
>>Also 'my'
>>has connotations of lexical scope, not dynamic scope. Consider
>>
>> # Alters the string in $_.
>> sub trim() { s/^\s+//; s/\s+$// }
>>
>> {
>> something $_; # local, or my, or what?
>> $_ = <FILE>;
>> trim();
>> tr/abc/def/;
>> s/fred/jim/;
>> print;
>> }
>>
>>'my $_' would not make the new value available to the called subroutine.
>
>This is exactly the point. In the scope of `my $_' the variable $_
>is, well, lexical. So you code trim() to take an argument - as it
>should if this is not a throw-away piece of code.
You've suggested one answer to the problem, but I don't consider it a
full solution because I don't agree with your 'should'. I don't see
anything wrong in principle with modifying $_ as a side-effect,
provided this is documented. In building subroutines a good rule of
thumb is 'do as the language and standard library do', and Perl's
commonly-used builtins s/// and tr/// do act on $_. They do not take
a reference argument.
So I would like to keep the existing global scoping of $_, and
essentially keep it as it is now; the only change is to have some
better version of 'local' that doesn't do strange things when the
localized variable previously contained a magic value. Then most uses
of 'local $_' - or 'local $anything_else' - could be replaced with
'better_local', and this particular deficiency of dynamic scoping
could go away.
Adding 'my $_' to the language to turn $_ into a lexically scoped
variable might be useful too, especially if this is how it will be in
Perl 6. I wonder if functions like the above trim() will be possible
in Perl 6? I am sure that s/// and chomp() will continue to operate
on $_ as they do now. One rule of thumb for building a 'clean'
language is that all builtin functions such as these should be
implementable in the language itself (or that there should not be any
builtin functions - which amounts to the same thing). It doesn't seem
right that chomp() should get special treatment in changing $_ while
user-defined functions should be unable to modify it. But this is
getting offtopic for perl5.
--
Ed Avis <e...@membled.com>
Does not matter much if done the first thing in a *script* (there is
no @_ yet). [Of couse, let me write it explicitly: *it* is *not* a
solution, since other components may expect $_ to be magical. Making
operations operate on (my $_) - if present - *is* a more or less
complete solution.]
> > This is another piece of serious misdesign of Perl: instead of having
> > special functions to configure Perl state, the state is kept in
> > zillions of special variables. Just look at $^H, for god sake!
>
> $^H and its evil twin %^H are not meant to be user visible, completely
> broken and likely to be replaced by something more sensible.
This is just a sign: first, understand that $^H is broken.
Understanding the rest of fly-by-variable scheme is also broken is the
next step (took me some time, sigh...).
> > my $_;
> >
> > may be a kind of such a pragma - all operations which were acting on
> > $_ start to act on (my $_).
>
> Interesting ; that could be done, first by removing the compile-time
> check that prevents from doing 'my $_', then by adding a new lexical
> hint meaning "we're in a scope where $_ is lexicalized", then by
> modifying the code that adds access to $_ to parameterless special
> functions to check for this hint, to lookup $_ in the current pad
> instead.
No, this is too slow. The offset of my $_ in the pad should be
actually stored in the OP itself at the compile time (as it is in
other ops working on temporary values or lexicals). Thus one needs to
do one of
a) an extra field in all the ops acting on $_;
b) a lexical-sibling opcode for all such ops;
c) explicitly put PADSV opcode into the OP tree.
a) blows memory requirement of a running program; c) slows down things
(extra opcode dispatch overhead); b) increases the size of perl
executabie (3-5K, I would think). I would prefer 'b'.
> However that's One Of The Things That Must Wait For A Proper Lexical
> Hint Mechanism.
There is no need to *wait* for anything. Doing (my $var) is already
supported, and already recognized by the optree builder.
Hope this helps,
Ilya
> >>>To save 3 keyspresses (and possibly get into a lot of trouble)?
> To write code which is in a straightforwward, idiomatic style (as
> often used in Perl documentation) and with an expectation it will work.
As you see, the "idiomatic" code "as often used in Perl documentation"
is not usable "in real life" (big applications). Big applications
should be coded in orthogonal style - so that one can easily predict
all the side effects and quirks.
This does not mean that I advocate a *complete* removal of
diagonality; but there should be a way to *disable* it - or at least
its most vicious kinds.
> I don't understand what you are getting at. Suppose a user U posted
> to this group complaining of a seeming bug in Perl and is answered by
> some other poster P:
>
> U: Whenever I use "hello $name" perl crashes. But 'hello ' . $name
> works fine.
> P: Why are you using string interpolation? It obviously causes
> problems.
> U: But I thought string interpolation would work. It should work.
> P: Why are you using it? Just to save keystrokes?
>
> I am sure this is not a fair representation of your argument but
> that's how it seems to me. There must be some point I'm missing.
String interpolation turns out to be (almost) straitforward part of
Perl. [The only quirk that comes to my mind immediately is that for
overloaded objects a non-intuiteve method is called.]
What we discuss is not theory; it is decided by practice. If a
particular constructs continues to bug people with *years* of
experience in Perl, *then* one can decide whether this construct was
beneficial or not. It is only one quirk (and the quirk which is
localized to overloading *designers*, not users), so it turns out that
string interpolation *is* beneficial.
> Assigning a value to $_, using regexp matching like /z/, and using
> 'local $_' are all straightforward bits of Perl code recommended in
> the standard documentation.
You behave as if "standard documentation" is something sacrosanct.
Get real, it is written by people, not communicated direct from g*d.
> If they don't work or do surprising
> things (and _really_ surprising things, not just the usual level of
> DWIMmery) then something is broken. Either the documentation can be
> fixed to add explicit warnings or perl can be changed or extended to
> make such constructs safer.
I compiled a new Perl online book from the Perl docs (5.8.1+ a minimal
useful collection of external modules - about 100 CPAN distributions).
It is 11M *compressed*! [I think external modules take no more than
20% of this.] Do you still want to "fix things" by documenting new
and new workarounds against *Perl problems*?
> But as I say below, I don't agree that there is anything special
> about $_ that makes such code bad. I think the problem is just the
> same with any global variable.
As I said, I could not agree less.
> >Or do you know a case when assignment to $_ has *more* benefits?
>
> As far as I can tell using $_ has few benefits beyond the syntactic.
> Most $_ uses can be mechanically translated to an equivalent construct
> using a named global variable. There are a few cases such as map()
> and grep() where using $_ is required by the language, although there
> too you can start off by assigning it to some other variable.
I think this constructs protect $_ *properly*, so they should not
cause problems like we discuss here.
> for coding style. Sometimes for performance or just for convenience I
> have written subroutines that modify a scalar in-place. This could be
> done by passing in a reference but it seems more in in tune with the
> language's builtins (s///, tr///) to modify $_.
You do not need pass-by-reference to modify things in place.
> >Just use *_ = \${'!!!'} at the top of your program, and all the
> >magical features of $_ disappear
>
> I don't think $_ has any magical features. As far as I can tell it is
> just an ordinary global variable which can be used to store scalars.
> The only difference from other global variables is in namespace
> resolution - $_ is accessible from all namespaces.
Nope. The major difference is that a lot of opcodes act on $_ by default.
> The magic of $_ is purely syntactic. '/z/' is an abbreviation for
> '$_ =~ /z/'.
It *acts* as such abbreviation, but is not. See -MO=Terse.
> 'while (<FH>)' is an abbreviation for
> 'while (defined($_ = <FH>))'. If these constructs are dangerous then
> anything using a non-lexical variable is dangerous.
Again, the real problem is psychological - if you need to write
defined($_ = <FH>) anyway, the chance that you do
my $line;
... defined($line = <FH>)
is much higher than if the alternative is just <FH>.
> There are two answers: avoid using global variables entirely (and not
> just $_, all of them, and package-scoped ones too)
Why? The rule is very simple: use non-lexicals *only* when you want
global visibility. Write `local' only if you *want* to assign a
temporary new value to a global variable.
These are very simple rules; simple both in the letter, and also in
execution. However, *it turns out* that the rule "do not use
operations which are defaulting to $_" is *hard* in execution.
Everybody with a lot of experience knows about it, but very few people
can consistenly restrain from this urge to save 3..10 keystrokes.
> It does seem that Perl 6 addresses some of the problems which bug me
> (in particular, it makes $_ a lexical not a global) and perhaps some
> of your gripes too. But it's vapourware ATM.
IMO, what I saw Perl 6 is *much much* worse in this department than
Perl 5. But now, when it is officially dead, there is little to
discuss...
> same conclusion from the opposite side: the language is irredeemably
> broken in some places, that some constructs are inherently unsafe and
> obviously not to be used in large programs, and so it is not worth
> trying to fix things.
I do not agree that this has a lot of relationship to my position.
> > my $_;
> >
> >may be a kind of such a pragma - all operations which were acting on
> >$_ start to act on (my $_).
>
> Hmm, so 'while (<>)' for example would have an implicit lexically
> scoped $_ inside the loop body.
Not exactly: it is going to scoped as usual: from the place 'my $_'
was declared, to the end of the scope. But `while(<>)' would indeed
operate on this lexical instead of ${*_{SCALAR}}.
> That would be one answer, but I think I'd prefer to have dynamic
> scoping available too - that is, the new value of $_ is available to
> called subroutines because it depends on the runtime life of the block
> not the location in source code of a line using $_.
The crucial point, IMO, is: how many words do you need to provide a
succinct but *complete* description of the feature. I suspect that
what you want is so weird, that it is much better just to advice
people to use
*_ = \my $auto;
> >>Like I say, I'm trying to work out conditions under which such
> >>constructs are safe to use.
> >
> >The answer is easy: none. In presense of tie()d values,
> >CORE::GLOBAL, and operator overloading, there is no useful construct
> >which can't call a random buggy subroutine.
>
> Then the conditions required are that other code doesn't do
> gratuitously strange things.
IMO, it does not make sense to provide non-local conditions. It is
just plain impossible to check in large-scale projects.
> code has overridden 'print' - unless I deliberately included a library
> which is documented to do that.
If the code had overridden CORE::GLOBAL::print that it continues doing
what it did before (e.g., for the purpose of logging, or debugging, or
whatever else), there is no need to document it LOUDLY. Likewise for
overloading.
The question is not about *intent* if tie(), overloading, or
overriding. I suppose that the intended functionality if this code is
correct.
Here is what I said: if due to *bugs* in code doing tie(),
overloading, or overriding, they leak changes to $_ outside, it is
impossible/very-hard to debug with the construct you advocate.
> >Now guess, when was the last time I was looking for who is changing
> >my array which should have been constant? Right, yesterday. (BTW,
> >the culprit is MakeMaker.)
>
> ...except that when it comes to MakeMaker, all bets are off ;-P.
> Still this is an exception. Most Perl libraries manage to do their
> job without causing such odd side-effects, and just as there is an
> unwritten contract that calling Date::Manip::ParseDate() will not
> cause an infinite loop or chew up ten megabytes of memory
There is no such contract with Perl. You never know how much
time/memory a particular operation takes.
> >How many peole can describe how many elements split /$re/, $a returns
> >for all possible values of $re and $a?
>
> That is another area of the language which needs cleaning up. But
> it's not quite the same as what's discussed above, since however
> strange the behaviour of 'split' may be, at least it does not have
> side effects of setting variables in some faraway and unrelated bit of
> code. Well, apart from $1, $2 and the other regexp magic vars :-(.
Again, a particular example which goes wrong. Yes, split() *does*
"setting variables in some faraway and unrelated bit of code". (But I
think we have a warning in such a situation - but again, this
particular warning makes some useful constructs very hard to use.)
> Yes, but seeing use of $_ in a program you expect it to be global. At
> least I would. It would be too surprising to see code that uses $_
> but doesn't get the global, dynamic-scoping behaviour.
This is a valid concern. One needs to weight the necessity to teach
people "with 5.10 $_ is not necessarily global - it follows the same
scoping rules as just as any other variable" versus teaching them how
to avoid the currently present mess.
Hope this helps,
Ilya
I misdescribed my proposal : its entirely compile-time. It's about
compiling a PADSV op instead of a GVSV for $_ as it's currently (to
get the global $_). So that would be probably something like your option
(c) below. Although (b) seems a better way to do it in fact.
>Thus one needs to
>do one of
>
> a) an extra field in all the ops acting on $_;
>
> b) a lexical-sibling opcode for all such ops;
>
> c) explicitly put PADSV opcode into the OP tree.
>
>a) blows memory requirement of a running program; c) slows down things
>(extra opcode dispatch overhead); b) increases the size of perl
>executabie (3-5K, I would think). I would prefer 'b'.
>
>> However that's One Of The Things That Must Wait For A Proper Lexical
>> Hint Mechanism.
>
>There is no need to *wait* for anything. Doing (my $var) is already
>supported, and already recognized by the optree builder.
What I was talking about is the need for "my $_" to act like a pragma.
I don't see another way to know whether perl is currently compiling a
scope in which $_ has been lexicalized.
--
Uninterruptedly is not *NIX
>>>> $_ = <FILE>;
>>>> /z/ && print "read a line containing 'z'\n";
>As you see, the "idiomatic" code "as often used in Perl
>documentation" is not usable "in real life" (big applications).
Even if this were the case, and $_ were unusable in anything but
one-liners, there is still a large body of code (including CPAN) which
contains such constructs. So we still need to worry about how to
retro-fit some measure of orthogonality and predictability onto it.
I think this is what you are addressing with your 'my $_' proposal.
It would let code such as the above be used more safely. My proposal
for 'better_local' has a similar aim, but it would mean changing most
existing 'local $_' to 'better_local $_', and adding the latter in
code whose author forgot to localize $_.
>Big applications should be coded in orthogonal style - so that one
>can easily predict all the side effects and quirks.
Well sure. So to make Perl a better language you can either remove
constructs such as '/z/', or try to de-quirk them.
As I said before, though, I don't see any real difference between
'/z/' and '$_ =~ /z/'. The syntactic convenience of a default string
variable doesn't in itself introduce quirks and unpredictable
behaviour. The code would be just as unpredictable if one were forced
to write it out in full.
>What we discuss is not theory; it is decided by practice. If a
>particular constructs continues to bug people with *years* of
>experience in Perl, *then* one can decide whether this construct was
>beneficial or not.
Yup. I think there are two quirks: the existence of a single global
$_ variable (which programmers are encouraged to use, although they
would normally stay away from globals), and the lack of any effective
means to localize global variables.
You could fix the former with 'my $_' but 'local' would still do odd
things when applied to other global variables which had magic. Still
maybe that would not matter much. You could fix the latter problem
with some better replacement for 'local', but then all code operating
on $_ would have to remember to call it.
>>Assigning a value to $_, using regexp matching like /z/, and using
>>'local $_' are all straightforward bits of Perl code recommended in
>>the standard documentation.
>
>You behave as if "standard documentation" is something sacrosanct.
>Get real, it is written by people, not communicated direct from g*d.
My point is exactly that the standard documentation is fallible. It
is recommending something that is unsafe. Therefore either the
documentation or the language needs to be fixed, maybe both.
>Do you still want to "fix things" by documenting new and new
>workarounds against *Perl problems*?
No, the best option is to fix or improve the language. I pointed to
the documentation to give more weight to the argument that Perl's
problems need to be fixed.
If some programmer found an obscure bit of code that had stupid
semantics, well it would be a problem with Perl but perhaps not an
important one. On the other hand if even the most simple things done
time and again even in tutorials and Perl's own documentation turn out
to be unsafe, that is surely a more serious bug.
So I agree with you, Perl has the problem and should be fixed. Citing
the documentation is just a way to back this up.
>>But as I say below, I don't agree that there is anything special
>>about $_ that makes such code bad. I think the problem is just the
>>same with any global variable.
>
>As I said, I could not agree less.
Could you say what the special properties of $_ are that make it
different from other globals? To me it seems that it just has a funny
name, that is all.
>>Sometimes for performance or just for convenience I have written
>>subroutines that modify a scalar in-place. This could be done by
>>passing in a reference but it seems more in in tune with the
>>language's builtins (s///, tr///) to modify $_.
>
>You do not need pass-by-reference to modify things in place.
Fair point, you can just pass a scalar and it's implicitly by
reference. Although this too is one of the strange and non-orthoganal
behaviours that makes it hard to build large Perl programs (consider
the example I posted earlier of calling foo($1), and the first line of
foo does a regexp match).
I'll admit there is not that much reason to write code which modifies
the global $_. Maybe it would be simplest to make $_ a lexical.
>>The magic of $_ is purely syntactic. '/z/' is an abbreviation for
>>'$_ =~ /z/'.
>
>It *acts* as such abbreviation, but is not. See -MO=Terse.
OK, let me rephrase: '/z/' is semantically equivalent to '$_ =~ /z/'.
>Again, the real problem is psychological - if you need to write
>defined($_ = <FH>) anyway, the chance that you do
>
> my $line;
> ... defined($line = <FH>)
>
>is much higher than if the alternative is just <FH>.
I think that's fair. It would be okay if 'while (<>)' bound $_ to a
new scalar inside the loop body, but alas...
>>There are two answers: avoid using global variables entirely (and
>>not just $_, all of them, and package-scoped ones too)
>
>Why? The rule is very simple: use non-lexicals *only* when you want
>global visibility. Write `local' only if you *want* to assign a
>temporary new value to a global variable.
The rule could be: use global variables only when you have a known
convention for the use of each one - that is, the global variable
should be something like $DEBUG_LEVEL which has a meaning, not
$RANDOM_SCALAR (also called $_) which has unrelated uses in different
bits of code.
Having decided on a global such as $DEBUG_LEVEL, you need to adopt a
convention that it won't hold magic values. This is so that blocks of
code which want to adjust the debug level temporarily can use 'local'
safely. That won't work if the old value was magic.
For $_, there can be no general agreement about what it is for. You
can follow some loose conventions such as no magic values (otherwise
'local' breaks), and not to change $_ without localizing it. But
these are not obvious and not all existing library code follows them,
so it may be safer to avoid $_ altogether.
>However, *it turns out* that the rule "do not use operations which
>are defaulting to $_"
Rather, 'do not use operations on $_'. If 'print' is bad, then
'print $_' is just as bad.
>>> my $_;
>>Hmm, so 'while (<>)' for example would have an implicit lexically
>>scoped $_ inside the loop body.
>
>Not exactly: it is going to scoped as usual: from the place 'my $_'
>was declared, to the end of the scope.
Ah, you confused me by calling it a 'pragma'. OK, it works more or
less the same as 'my $anything_else'.
>>That would be one answer, but I think I'd prefer to have dynamic
>>scoping available too - that is, the new value of $_ is available to
>>called subroutines because it depends on the runtime life of the
>>block not the location in source code of a line using $_.
>
>The crucial point, IMO, is: how many words do you need to provide a
>succinct but *complete* description of the feature.
I have already given such a description. I want
{
A
better_local $v = X;
B
}
to be semantically equivalent to
{
A
for $v (X) {
B
}
}
where A and B are any list of statements, $v is any global variable
name, and X is any expression.
'better_local $v;' should be equivalent to 'better_local $v = undef;'.
>>>>Like I say, I'm trying to work out conditions under which such
>>>>constructs are safe to use.
>>Then the conditions required are that other code doesn't do
>>gratuitously strange things.
>
>IMO, it does not make sense to provide non-local conditions. It is
>just plain impossible to check in large-scale projects.
Sadly, this is life. And not just in Perl. In C, for example, you
have to lay down conditions that other code will not use pointers to
scribble over your memory.
It is impossible to check - you don't check. You make requirements in
order that you don't have to check. When calling a library, you
assume that it honours its documented postconditions and (implicitly)
doesn't do other strange things like replacing CORE::print or
overwriting memory, unless these are documented.
>Here is what I said: if due to *bugs* in code doing tie(),
>overloading, or overriding, they leak changes to $_ outside, it is
>impossible/very-hard to debug with the construct you advocate.
Ah okay. Yes I think this is true. A construct 'better_local $_'
helps only for code that remembers to use it. You could still be
tripped up by some routine that changes $_ without asking (and this is
too easy to do). Making $_ a lexical is better, then, because you
can't 'forget' to do lexical scoping.
>>Most Perl libraries manage to do their job without causing such odd
>>side-effects, and just as there is an unwritten contract that
>>calling Date::Manip::ParseDate() will not cause an infinite loop or
>>chew up ten megabytes of memory
>
>There is no such contract with Perl. You never know how much
>time/memory a particular operation takes.
Like I said, there is an _unwritten_ contract. If the 'hello world'
program died with out of memory, I'd report that as a bug. There are
not many guarantees, true, but there are some. The fact that they're
not exactly specified doesn't mean they don't exist. Maybe
Perl-the-language makes no guarantees about time or space complexity,
but perl-the-implementation does.
--
Ed Avis <e...@membled.com>
Please check -O=Terse first. There is *no* GVSV for $_. That's the point.
> What I was talking about is the need for "my $_" to act like a pragma.
> I don't see another way to know whether perl is currently compiling a
> scope in which $_ has been lexicalized.
Perl_padmy(). (sp?)
Hope this helps,
Ilya
> As I said before, though, I don't see any real difference between
> '/z/' and '$_ =~ /z/'. The syntactic convenience of a default string
> variable doesn't in itself introduce quirks and unpredictable
> behaviour. The code would be just as unpredictable if one were forced
> to write it out in full.
Your assessment is based on presumption that programming is "like a
science". This presumption turns out (in my experience) to be not
that useful. Programming is about psychology of programmers. From
the point of view of lazyness and hubris, the major difference between
/z/ and $_ =~ /z/ is that nobody will use the second variant.
One would use
my $line = ....;
$line =~ /z/;
instead - without feeling inconvenienced. However, when given the
task of rewriting /z/ to the construct above, one would feel *very*
inconvenienced. And it is the feelings which matter.
[Well, I do not want to claim that science is not about psychology of
scientists - but this is an orthogonal topic ;-]
> Yup. I think there are two quirks: the existence of a single global
> $_ variable (which programmers are encouraged to use, although they
> would normally stay away from globals), and the lack of any effective
> means to localize global variables.
You *still* did not provide any example to substantiate the second
claim. [I assume that by localization you do not mean the current
semantic of injecting a new value in "an existing container".]
> So I agree with you, Perl has the problem and should be fixed. Citing
> the documentation is just a way to back this up.
Thanks, I was confused by these citations.
> I'll admit there is not that much reason to write code which modifies
> the global $_. Maybe it would be simplest to make $_ a lexical.
*That* part of Perl6 design I wholeheartedly agree with. But we can
preserve backward-compatibility by making Perl5 behave the same in
scope of my $_.
> Having decided on a global such as $DEBUG_LEVEL, you need to adopt a
> convention that it won't hold magic values. This is so that blocks of
> code which want to adjust the debug level temporarily can use 'local'
> safely. That won't work if the old value was magic.
This works perfectly well if the old value was magical. Try it with
the (global) $ENV{PATH}. What do you have in mind?
> >However, *it turns out* that the rule "do not use operations which
> >are defaulting to $_"
>
> Rather, 'do not use operations on $_'. If 'print' is bad, then
> 'print $_' is just as bad.
Fine; but this is just a part of another rule: "do not use globals
unless...".
> >Not exactly: it is going to scoped as usual: from the place 'my $_'
> >was declared, to the end of the scope.
>
> Ah, you confused me by calling it a 'pragma'. OK, it works more or
> less the same as 'my $anything_else'.
Right.
> I have already given such a description. I want
>
> {
> A
> better_local $v = X;
> B
> }
>
>
> to be semantically equivalent to
>
> {
> A
> for $v (X) {
> B
> }
> }
Do you know a good *complete* description what `for $v' does? [As
opposed to `for my $v', which has a very simple semantic.] All I
could find is (perlsyn 5.8.1)
foreach probably won't do what you expect if VAR is a tied
or other special variable. Don't do that either.
This does not help your clause, right?
> Sadly, this is life. And not just in Perl. In C, for example, you
> have to lay down conditions that other code will not use pointers to
> scribble over your memory.
C is a very simple language. With Perl, the probability that the code
you `use' is "as good as that" is pretty low.
Thanks for a valuable discussion,
Ilya
On Mon, Oct 13, 2003 at 06:01:55PM +0000, Ilya Zakharevich <nospam...@ilyaz.org> wrote:
> [A complimentary Cc of this posting was sent to
> Rafael Garcia-Suarez
> <rgarci...@free.fr>], who wrote in article <slrnbokqai.m5a...@rafael.serd.lyon.hexaflux.loc>:
> > I misdescribed my proposal : its entirely compile-time. It's about
> > compiling a PADSV op instead of a GVSV for $_ as it's currently (to
> > get the global $_).
>
> Please check -O=Terse first. There is *no* GVSV for $_. That's the point.
For those not already familiar with the Terse backend, I will note
that Terse is deprecated; use -MO=Concise instead. (Yes, I know
that perlhack.pod is out of date in this respect.)
There usually is a gvsv. m//, s///, and y/// (and unpack in blead)
seem to be the exception rather than the rule. I see violent
agreement that there should be way to have lexical $_ in a given
scope. I even see agreement that C< my $_ > is a reasonable way to do
this (though I see some problems if it leaks into anonymous subs and
evals, as lexicals usually do). Implementation should be discussed on
perl5-porters.
On Mon, Oct 13, 2003 at 05:31:40PM -0700, Ilya Zakharevich <il...@Math.Berkeley.EDU> wrote:
> > that Terse is deprecated; use -MO=Concise instead. (Yes, I know
> > that perlhack.pod is out of date in this respect.)
>
> Thanks, it contains changes which I TODOing for many years...
I especially like -MO=Concise,-exec
> > I see violent agreement that there should be way to have lexical $_
> > in a given scope. I even see agreement that C< my $_ > is a
> > reasonable way to do this (though I see some problems if it leaks
> > into anonymous subs and evals, as lexicals usually do).
>
> They *should* leak into evals (a year ago %^H would not leak - and
> this is a major bug). And I see no difference between named and
> anonymous subs; why do you think latter should be treated differently?
I would usually want to say my $_ in a sub, and subs usually don't
contain named subs, so I only mentioned anonymous subs. To clarify
myself, my $_ *should* leak into eval/subs, because that's how
lexicals work. But the underlying reason for which I would want to
say my $_ is to have a local scratch variable, and being visible in
eval/subs isn't needed for that purpose and may in some cases even be
undesirable.
> ==================================================================
>
> BTW, another related issue: lexically scoped info should leak into
> <DATA> as well. E.g., consider a SelfLoad()ing code: it is read from
> <DATA>, but there is no way for the SelfLoader to see that the module
> asked for `use strict'. - so no strictness is done.
That's really something that has to be implemented in the SelfLoading
code. (That is, SelfLoader::AUTOLOAD needs to do something other than
just a simple string eval.) But I agree that perl needs to provide a
way to do it.
> One possible implementation: $^H and %^H should be stored (e.g., in
> *{'<DATA>'}) when __DATA__ token is processed. Then SelfLoader (or
> any other code) can inspect these, and setup the environment for the
> code read from <DATA> accordingly.
I've been hoping that %^H and the non-working parts of $^H will die a
quick and merciful death sometime soon. Have you seen MJD's trial
balloon "Lexical Pragma" patch from last month? The __DATA__ idea
doesn't extend to AutoLoader which doesn't AIUI use a __DATA__ marker.
: To clarify
: myself, my $_ *should* leak into eval/subs, because that's how
: lexicals work. But the underlying reason for which I would want to
: say my $_ is to have a local scratch variable, and being visible in
: eval/subs isn't needed for that purpose and may in some cases even be
: undesirable.
If the eval or sub uses $_ then surely it could declare its own my $_
which would hide the one from out side that has "leaked" in.
Thanks, it contains changes which I was TODOing for many years...
> There usually is a gvsv. m//, s///, and y/// (and unpack in blead)
> seem to be the exception rather than the rule.
perl -MO=Concise -wle "print sin"
7 <@> leave[1 ref] vKP/REFC ->(end)
1 <0> enter ->2
2 <;> nextstate(main 1 -e:1) v ->3
6 <@> print vK ->7
3 <0> pushmark s ->4
5 <1> sin[t2] sK/1 ->6
- <1> ex-rv2sv sK/1 ->5
4 <$> gvsv(*_) s ->5
Yes, looks like you are right. *These* indeed should be extremely
easy to lexicalize!
> I see violent agreement that there should be way to have lexical $_
> in a given scope. I even see agreement that C< my $_ > is a
> reasonable way to do this (though I see some problems if it leaks
> into anonymous subs and evals, as lexicals usually do).
They *should* leak into evals (a year ago %^H would not leak - and
this is a major bug). And I see no difference between named and
anonymous subs; why do you think latter should be treated differently?
==================================================================
BTW, another related issue: lexically scoped info should leak into
<DATA> as well. E.g., consider a SelfLoad()ing code: it is read from
<DATA>, but there is no way for the SelfLoader to see that the module
asked for `use strict'. - so no strictness is done.
One possible implementation: $^H and %^H should be stored (e.g., in
*{'<DATA>'}) when __DATA__ token is processed. Then SelfLoader (or
any other code) can inspect these, and setup the environment for the
code read from <DATA> accordingly.
Comments?
Ilya
> > BTW, another related issue: lexically scoped info should leak into
> > <DATA> as well. E.g., consider a SelfLoad()ing code: it is read from
> > <DATA>, but there is no way for the SelfLoader to see that the module
> > asked for `use strict'. - so no strictness is done.
>
> That's really something that has to be implemented in the SelfLoading
> code. (That is, SelfLoader::AUTOLOAD needs to do something other than
> just a simple string eval.) But I agree that perl needs to provide a
> way to do it.
I think we are talking on crosspurposes. Of course, the actual code
to setup the duplicate of the lexical environment which was present at
the moment of __DATA__ should be in SelfLoader. However, currently
this lexical environment *disappears* when the module is compiled.
What I'm talking about is that the Perl Core should *store* a copy of
this environment somewhere where SelfLoader (or other code) can fetch
it from.
Hope this helps,
Ilya
>>I think there are two quirks: the existence of a single global $_
>>variable (which programmers are encouraged to use, although they
>>would normally stay away from globals), and the lack of any
>>effective means to localize global variables.
>
>You *still* did not provide any example to substantiate the second
>claim. [I assume that by localization you do not mean the current
>semantic of injecting a new value in "an existing container".]
I did, earlier in this thread:
sub foo {
local $_ = "hello";
print $_;
}
my $str = 'abc';
$str =~ /(\w+)/;
for ($1) {
print "matched word: $1\n";
foo();
}
You may argue that the real problem is using a global variable ($_) at
all, or using a global for different things in different places.
Still, there have been languages which had only global variables and
dynamic scope, and they were not always unusable. With a better
replacement for 'local' the above code would be safe.
>>Having decided on a global such as $DEBUG_LEVEL, you need to adopt a
>>convention that it won't hold magic values. This is so that blocks
>>of code which want to adjust the debug level temporarily can use
>>'local' safely. That won't work if the old value was magic.
>
>This works perfectly well if the old value was magical. Try it with
>the (global) $ENV{PATH}. What do you have in mind?
Ah - phrased badly - what I meant was that you cannot in general use
'local' safely if the old value was magic. See above.
I think there is room for two keywords: the current 'local' which
calls STORE, and a stronger alternative which has the semantics I
mentioned.
>>to be semantically equivalent to
>>
>> {
>> A
>> for $v (X) {
>> B
>> }
>> }
>
>Do you know a good *complete* description what `for $v' does?
You've got me there. It was an assumption in my definition that the
rest of the language has a defined semantics - and we both know this
is not true.
Still, at least I can say that as far as having unclear semantics, my
proposal is no worse than the rest of the language. If you're
concerned about cleaning up the meaning of Perl then defining 'for $v'
and a hundred other things would be a good place to start; there is no
_particular_ fault with the above definition.
> foreach probably won't do what you expect if VAR is a tied
> or other special variable. Don't do that either.
>
>This does not help your clause, right?
Actually it's what I mean. I think the docs are warning that if VAR
is magic, then 'for VAR' will temporarily lose the magic - that is,
bind the variable name to a whole new scalar rather than (say) just
STOREing a value in the existing magic scalar. In some cases, for
example when you want to completely ignore the previous value (magical
or not) of VAR, this is the behaviour you want.
--
Ed Avis <e...@membled.com>
sub foo {
my $str = "hello";
print $str;
}
> You may argue that the real problem is using a global variable ($_) at all
You got it. I do not consider this usage as deserving any attention.
> >>Having decided on a global such as $DEBUG_LEVEL, you need to adopt a
> >>convention that it won't hold magic values. This is so that blocks
> >>of code which want to adjust the debug level temporarily can use
> >>'local' safely. That won't work if the old value was magic.
> >
> >This works perfectly well if the old value was magical. Try it with
> >the (global) $ENV{PATH}. What do you have in mind?
>
> Ah - phrased badly - what I meant was that you cannot in general use
> 'local' safely if the old value was magic. See above.
Of couse you can. If you use it as `local' - to temporary change a
value of a container. See $ENV{PATH}.
If you want to use is as `my', then, well, do not.
> Still, at least I can say that as far as having unclear semantics, my
> proposal is no worse than the rest of the language.
The purpose of this discussion is to make the language better than the
current (pitiful) state. Do you want to do the improvements while
keeping the old style?
> > foreach probably won't do what you expect if VAR is a tied
> > or other special variable. Don't do that either.
> >
> >This does not help your clause, right?
>
> Actually it's what I mean. I think the docs are warning that if
I doubt it. This is the beauty of documenting things as "they won't
do what you expect" - and stopping at that. Apparently, you and I
expect different things. ;-)
Thanks again,
Ilya
>>Ah - phrased badly - what I meant was that you cannot in general use
>>'local' safely if the old value was magic.
>Of couse you can. If you use it as `local' - to temporary change a
>value of a container. See $ENV{PATH}.
Let me rephrase again: you may write code to use 'local' to
temporarily give a new value to a non-lexical variable, but you cannot
write a line of code that is safe in general. Eg
our $global;
sub foo {
local $global = 'goodbye';
print $global;
}
This is broken by
my $str = 'hello';
$str =~ /(.+)/ or die;
for $global ($1) { foo() }
>If you want to use is as `my', then, well, do not.
Agreed, provided there is something to use instead (eg 'my $_').
--
Ed Avis <e...@membled.com>
What has this to do with globality of $global? Indeed, you can't pass
$1 to a subroutine as an argument (without major complications). The
fact that you emulate argument-passing via a global is not very
relevant, IMO.
Thanks,
Ilya
>> our $global;
>> sub foo {
>> local $global = 'goodbye';
>> print $global;
>> }
>>
>>This is broken by
>>
>> my $str = 'hello';
>> $str =~ /(.+)/ or die;
>> for $global ($1) { foo() }
>
>What has this to do with globality of $global?
It has to do with the 'local' keyword and the way it acts, which is
not as advertised (IMHO). I know what the behaviour of 'local' is and
why it's that way, but the keyword is mismarketed.
Either there should be some better supplement to 'local' for truly
giving a non-lexical a temporary value (without caring what the value
was before), or else 'local' should come with a health warning. This
is the same choice I mentioned earlier: either fix the language, or
fix the documentation.
>Indeed, you can't pass $1 to a subroutine as an argument (without
>major complications).
That is another wart to fix (or at least document thoroughly).
--
Ed Avis <e...@membled.com>
To save three keypresses and not get into a lot of trouble by not
doing this when it is not safe to do, ie when calling functions which
randomly assign to globals instead of rebdinging them as appropriate.
>> >It is nice that it can be omited in one-liners; however, I do not
>> >think that the fact that one can omit it benefits larger programs.
>
>> I don't agree, given that a well-written large program will usually be
>> broken up into small, relatively self-contained routines.
>
> If you want to do this, use something else than Perl.
Why?
> In my experience, most large Perl programs work due to coincidences
> only. You cannot make things "relatively self-contained" with the
> current state of diagonality - there are too many unexpected side
> effects. [Of course, one can argue about how relative is your
> "relatively". ;-]
You can.
>> I don't see anything wrong in saying 'foreach (red green blue) {
>> ... }' as part of a simple five-line function, even if that function
>> is part of a 50kloc project.
>
> You see: you use a construct with *enormous* side effects, and claim
> that it is save to use in 50kloc project. How are you going to debug
> things if this function calls some other function (e.g, via tie() or
> overloading), and this other function happens to set $_?
Very simple: The debugger will tell me that the value changed due to a
bug in someone elses' code and I will then fix it there.
>> >>BTW - I'm not advocating the removal of 'local' from the language,
>> >>only the addition (or discovery) of some other mechanism which
>> >>really does make a block of code unaffected by whatever the previous
>> >>value of some global was, and makes the code executed after that
>> >>block returns unaffected by whatever the block did with the global.
>> >
>> >I'm confused - do not you mean `my' here?
>>
>> No, because 'my' creates a new lexical variable and (consequently?)
>> would not work with $_.
>
> But you advocate a change to the language anyway. Why not make `my
> $_' do what people expect?
Because local does dynamic scoping and this is a useful feature
(imported from Lisp and not from C++).
Sorry, I can't understand what you mean here. A chunk of code may be
a better explanation.
> >> I don't agree, given that a well-written large program will usually be
> >> broken up into small, relatively self-contained routines.
> >
> > If you want to do this, use something else than Perl.
>
> Why?
I wonder: did you read the rest of the thread? Anyway, the
explanation was that you can't do anything "small" in Perl. "Small"
means "bite-size", means "easy to grasp in its entirety". However,
due to diagonality, there is very few ops in Perl effects of which can
be *completely* described in less than 20 pages of documentation.
[Witness Perl docs: my electronic book for 5.8.1 is 11M *compressed*.]
> > In my experience, most large Perl programs work due to coincidences
> > only. You cannot make things "relatively self-contained" with the
> > current state of diagonality - there are too many unexpected side
> > effects. [Of course, one can argue about how relative is your
> > "relatively". ;-]
> You can.
Please share your credentials to dismiss my arguments in less than 3 words. ;-)
> > You see: you use a construct with *enormous* side effects, and claim
> > that it is save to use in 50kloc project. How are you going to debug
> > things if this function calls some other function (e.g, via tie() or
> > overloading), and this other function happens to set $_?
>
> Very simple: The debugger will tell me that the value changed due to a
> bug in someone elses' code and I will then fix it there.
LOL! OK, here is the situation I was fighting this bug in the last
time: an equivalent of
perl -MCPAN -e "test Bundle::Blah"
would not. Now: which program should I apply debugger to; which
variable should I watch changed; moreover, please describe how would I
distinguish about 1e6 *legitimate* changes to the variable from the
faulty one?
> >> >>value of some global was, and makes the code executed after that
> >> >>block returns unaffected by whatever the block did with the global.
> >> >
> >> >I'm confused - do not you mean `my' here?
> >>
> >> No, because 'my' creates a new lexical variable and (consequently?)
> >> would not work with $_.
> >
> > But you advocate a change to the language anyway. Why not make `my
> > $_' do what people expect?
>
> Because local does dynamic scoping and this is a useful feature
> (imported from Lisp and not from C++).
I suspect more and more that you did not get study the discussion in
question before posting. The example in question is one where dynamic
scoping is not a desired feature; local() is used only to cover other
Perl problems (hide a variable), not to have new value which is
visible from other code.
BTW, if reading a long discussion is error-prone: it is *me* who
advocates "local() should be used for dynamic scope effects only"
mantra.
Hope this helps,
Ilya
$methods[scan] = sub {
local $_; # we want our own
while (<$fh>) { # a lexical from an outer shared scope(*)
++$lineno;
s/\#.*$//;
s/^\s+//;
s/(\S)?\s+$/$1/;
/^$/ && do {
next if $state == SKIP_BLANKS;
return TOK_BLANK;
};
$_[0] = $_;
return TOK_NORMAL;
}
return TOK_EOF;
};
*) Closures are fun, but tend to generate flames from
Java-fans ...
If I understand this correctly, it is meant to be a way of
establishing a fresh symbol table entry for a well known name, which
is the only way implicit variables, like in the while-diamond-loop
(nice term), can be done, because the name must be known to the
compiler that has to look for the value somewhere.
>> >> I don't agree, given that a well-written large program will usually be
>> >> broken up into small, relatively self-contained routines.
>> >
>> > If you want to do this, use something else than Perl.
>>
>> Why?
>
> I wonder: did you read the rest of the thread?
It is not accessible to me.
> Anyway, the explanation was that you can't do anything "small" in
> Perl. "Small" means "bite-size", means "easy to grasp in its
> entirety". However, due to diagonality, there is very few ops in
> Perl effects of which can be *completely* described in less than 20
> pages of documentation.
This eventually a problem of the (a) perl-program, but not a problem of
the perl-language.
>> > In my experience, most large Perl programs work due to coincidences
>> > only. You cannot make things "relatively self-contained" with the
>> > current state of diagonality - there are too many unexpected side
>> > effects. [Of course, one can argue about how relative is your
>> > "relatively". ;-]
>
>> You can.
>
> Please share your credentials to dismiss my arguments in less than 3
> words. ;-)
I happen to know that nothing in the program where the cited code
comes from touches $_ because I have written it and I didn't loose
track of variable usage because I kept each structural unit small and
self-contained in such a way that interfaces are explicit.
>> > You see: you use a construct with *enormous* side effects, and claim
>> > that it is save to use in 50kloc project. How are you going to debug
>> > things if this function calls some other function (e.g, via tie() or
>> > overloading), and this other function happens to set $_?
>>
>> Very simple: The debugger will tell me that the value changed due to a
>> bug in someone elses' code and I will then fix it there.
>
> LOL! OK, here is the situation I was fighting this bug in the last
> time: an equivalent of
>
> perl -MCPAN -e "test Bundle::Blah"
>
> would not. Now: which program should I apply debugger to; which
> variable should I watch changed; moreover, please describe how would I
> distinguish about 1e6 *legitimate* changes to the variable from the
> faulty one?
If I have something like the code above, the value of $_ should not
change except when I willfully change it (like in the 'strip
whitespace and comments'-part). If it does nevertheless, I can track
this down to the line where it does and if something gets called there
implicitly, some part of the code I am using (including modules
eventually, though I tend to avoid them for exactly this reason) must
be executed there and this code is accessible to me.
>> > But you advocate a change to the language anyway. Why not make `my
>> > $_' do what people expect?
>>
>> Because local does dynamic scoping and this is a useful feature
>> (imported from Lisp and not from C++).
>
> I suspect more and more that you did not get study the discussion in
> question before posting. The example in question is one where dynamic
> scoping is not a desired feature; local() is used only to cover other
> Perl problems (hide a variable), not to have new value which is
> visible from other code.
But it is. In this case, it is implicitly 'visible' to the compiler,
which is certainly 'other code'.
> BTW, if reading a long discussion is error-prone: it is *me* who
> advocates "local() should be used for dynamic scope effects only"
> mantra.
As a matter of fact, I use it for symbol table manipulation, because
this is a very useful thing to be able to do.
> >> > What for? To save 3 keyspresses (and possibly get into a lot of
> >> > trouble), or something deeper?
> >> To save three keypresses and not get into a lot of trouble by not
> >> doing this when it is not safe to do, ie when calling functions which
> >> randomly assign to globals instead of rebdinging them as appropriate.
[example skipped]
> If I understand this correctly, it is meant to be a way of
> establishing a fresh symbol table entry for a well known name, which
> is the only way implicit variables, like in the while-diamond-loop
> (nice term), can be done, because the name must be known to the
> compiler that has to look for the value somewhere.
Since the example you quoted has no relation to either "randomly
assign to globals" reference, or "fresh symbol table entry", and it
does not need local() (as opposed to my()), it is hard to understand
your train of thought...
> > I wonder: did you read the rest of the thread?
> It is not accessible to me.
Enter
"bug or gotcha" group:*perl.moderated author:Zakharevich
into <URL:http://www.google.com/grphp?hl=en>. Go to the "View Thread".
> > Anyway, the explanation was that you can't do anything "small" in
> > Perl. "Small" means "bite-size", means "easy to grasp in its
> > entirety". However, due to diagonality, there is very few ops in
> > Perl effects of which can be *completely* described in less than 20
> > pages of documentation.
> This eventually a problem of the (a) perl-program, but not a problem of
> the perl-language.
??? I'm not discussing any particular program.
> >> > In my experience, most large Perl programs work due to coincidences
> >> > only. You cannot make things "relatively self-contained" with the
> >> > current state of diagonality - there are too many unexpected side
> >> > effects. [Of course, one can argue about how relative is your
> >> > "relatively". ;-]
> I happen to know that nothing in the program where the cited code
> comes from touches $_ because I have written it and [...]
Note that we are discussing "large Perl programs". Something one
person wrote can't be "large" by definition. I recommend reading the
whole thread before you post again.
Hope this helps,
Ilya
I think of the "value" of a glob being the GP (the thing that gets
assigned when you say *a = *b, that contains the scalar, array, hash,
etc.). So even for local *gv, it is the value that local affects, not
the container.
Kudos to Rafael for coming up with a preliminary patch to allow my $_.