
aaron at priven
Jul 9, 2012, 12:32 PM
Post #7 of 14
(194 views)
Permalink
|
|
Re: [perl #114020] given should localize topic, not lexicalize topic
[In reply to]
|
|
Thanks for pointing out that thread. The problem with the "we're handing them their own rope and they can decide how much to use" position is that most people haven't been following this issue for years and aren't going to understand why $_ is different from every other lexical variable. And it is. Only $_ (and sometimes $a and $b, but we don't use "my" on those either) is used as the placeholder variable in called builtins and subroutines. This causes problems with lots of called routines -- ones like Text::Trim, which use $_ as a default, and like List::Util::first, which use $_ as the placeholder variable in a block. Of course it works fine on core builtins, because they've been hacked to handle it. And it's possible for some (but not all -- see below) called routines to handle lexical $_ via the _ prototype, but of course, most don't, and it's not at all obvious to someone not familiar with the issue why some calling routines will handle lexical $_ and some won't. And, of course, the fact that it *is* possible makes lexical $_ not entirely lexical... Most people won't understand this unless they are told, and there's no mention of this problem anywhere in the docs that I know of, except for entries in old perldeltas, which just point people to rt #67694. That is insufficient. If people haven't been following this issue for years end up using my $_ for the same reason they use my $whatever -- because after all, lexical is better, otherwise why would perl 5 have introduced my in the first place? -- they're not being handed rope. They're being handed a loaded gun, without a class in gun safety. And people like Abigail have "done almost two decades of preaching 'use my, not local'". I do not know enough about what might happen if perl's behavior were changed to suggest eliminating lexical $_. Maybe it should; maybe not; I don't know. I do know that the documentation in perlvar is not enough to help most people understand whether to use it or not, or why using it might not work the way they expect. -- I will point out again the other issue I have with lexical $_, which is that calling routines can use it as a default only sometimes, because the _ prototype imposes scalar context. You can't create a function that works like chop or chomp, where it takes any number of arguments but defaults to $_. Here's what I wrote on that -- I think I've linked to it before here but not posted it on perl5-porters. (It's originally from http://perlmonks.org/?node_id=958820 ) So, one of my favorite pieces of perl is Text::Trim, which uses contexts to do Just The Right Thing. Here is the trim() function, with some comments that I wrote: sub trim { @_ = @_ ? @_ : $_ if defined wantarray; # When the caller is looking for a return value # (not void context), make a copy of the arguments, # so the original value is not changed. # If there are no arguments passed, # copy the value of $_ instead. for (@_ ? @_ : $_) { next unless defined; s/\A\s+//; s/\s+\z// } # If @_ contains any values, perform the # substitution on all defined values. If @_ contains # no values, perform the substitution on $_ instead. return @_ if wantarray || !defined wantarray; # return the changed values in array context # or (for a reason which escapes me) void context. if (my @def = grep defined, @_) { return "@def" } else { return } # In scalar context, return the results of # the substitution on all # defined values, if any. Otherwise just return. } This code is pretty hard to read, mostly because of the punctuation variables. But it allows the caller to do @trimmed = trim(@not_trimmed); or foreach (@untrimmed) { say trim; } or trim(@data); And the results make sense. But, as with so many things, it doesn't work with lexical $_. I thought maybe I could get this to work with the new underscore _ prototype, but unfortunately that imposes scalar context on the argument. In other words, sub trim (_;@) { # ... as above } my @data = (' a', ' b ' , 'c '); say trim (@data); displays not "abc" but "3", since that's the value of @data in scalar context (the number of elements). I can't think of any way around this that allows the flexibility of the Text::Trim calling conventions and also the use of lexical $_. Any ideas? On Jul 8, 2012, at 5:30 PM, Chris Prather wrote: Er well this *is* Perl, enough rope, shoot foot ... yada yada yada. The last time I remember this coming up it was shown pretty much that no matter *what* happened we would be letting people subtly break their code. See also Ric's epiphany: http://www.nntp.perl.org/group/perl.perl5.porters/2011/11/msg178998.html -Chris
|