Re: loop surprise
by Athanasius (Archbishop) on Apr 03, 2018 at 13:34 UTC
|
| [reply] [d/l] [select] |
|
Ok, that explains it, but I don't quite get the rationale for doing it this way...
If I wanted a localized variable I write the loop as "for my $j (...)".
If I explicitly use "for $i" I make clear my intention of using a previously introduced variable.
Why perl then insists on knowing better and localizing it is counter-intuitive to me and at the moment I don't see any reason why it should be implemented like that (but there probably is one)...
| [reply] |
|
Hi morgon,
I wouldn't say it's that Perl "knows better" so much as that it's a convenience for being able to modify the data you're iterating over.
Note that, because it's only a foreach loop that acts this way, and for is this context is just an alias for the same thing, if you want the behavior you were expecting you can use the 3-arg form of a for loop:
use strict;
my $i = "whatever";
for ($i = 1; $i <= 10; $i++) {
last if $i == 7;
}
print "$i\n"; # prints "7" instead
And believe it or not, you could even make it a 3-arg foreach loop (which is kinda counter-intuitive, but again, "for" and "foreach" are interchangeable):
use strict;
my $i = "whatever";
foreach ($i = 1; $i <= 10; $i++) {
last if $i == 7;
}
print "$i\n"; # still prints "7"
say
substr+lc crypt(qw $i3 SI$),4,5
| [reply] [d/l] [select] |
|
|
|
|
> get the rationale for doing it this
This was often discussed already, have a look into the archives if you want more details.°
IIRC it's because this behaviour of localizing the loop var is older (read Perl4) than lexicals.
Rule of thumb: never try to reuse an outer var as loop var in foreach... see also PBP advice to always for my $x (...) .
°) it leads to very confusing results if the loop creates subs closing over the loopvar.
| [reply] [d/l] |
Re: loop surprise
by toolic (Bishop) on Apr 03, 2018 at 13:35 UTC
|
This is documented in Compound Statements
If the variable is preceded with the keyword my, then it is lexically scoped, and is therefore visible only within the loop. Otherwise, the variable is implicitly local to the loop and regains its former value upon exiting the loop. If the variable was previously declared with my, it uses that variable instead of the global one, but it's still localized to the loop. This implicit localization occurs only in a foreach loop.
The variable does change value within the loop, as you can see with print:
for $i (1..10) {
last if $i == 7;
print "in loop $i\n";
}
| [reply] [d/l] |
[OT]: Re: loop surprise (unsurprising D foreach)
by AnomalousMonk (Archbishop) on Apr 03, 2018 at 21:17 UTC
|
<tangent>
Interestingly (well, to me anyway), the D language also has a Perlish
foreach (and foreach_reverse) loop that is distinct from its C-ish for-loop. The names for and foreach are not synonymous, however, as they are in Perl, perhaps thereby avoiding some confusion. In general, D, with its intimate embrace of associative arrays, foreach loops and a few other features, has for me an evocative resemblance to Perl — well, if you squint your eyes a bit and look at it from just the right angle.
</tangent>
Give a man a fish: <%-{-{-{-<
| [reply] [d/l] [select] |
|
| [reply] |
Re: loop surprise
by Your Mother (Archbishop) on Apr 03, 2018 at 17:42 UTC
|
Probably making the (undeclared) loop $i a syntax error would be best but it looks like the ship has sailed. An error was what I would have guessed seeing your code because it never in a million years would occur to me to repurpose a variable that way and I'd definitely be frustrated with any code, and the person responsible, I had to work with that did it.
| [reply] [d/l] |
|
Personally, I wouldn't break out on a condition related to the value of $i itself in such a loop, but I often run across circumstances such that I want to use the loop variable to store the last condition that was valid, when looping through a list of valid or invalid conditions. For example,
my $condNum = 0;
for $condNum ( 1 .. 10 ) {
forceSituation( $conditions[condNum] );
my $result = measureSituation();
push @results, $result;
last if $result->is_error();
more_manipulation(); # possibly do more stuff for this condition,
+but only if it's not an error
}
datalog( value => $condNum, llim => 9.9, hlim => 10.1, name => 'number
+ of situations tested' );
datalog( value => fn(@results), llim => -2.7182818, hlim => 3.1415926,
+ name => 'result of those situations' )
... That loop wouldn't work in perl. But it doesn't seem an abuse of the loop counter, to me, to use the loop counter as the indicator of how many situations were actually tested. The code above seems more natural to me than my $lastCondNum = 0;
for my $condNum ( 1 .. 10 ) {
...
$lastCondNum=$condNum, last if $result->is_error()
...
}
...
Why require a second variable just to store the last condition number it happened to be in, when the loop variable seems a natural storage device for that information?
(In these situations, I'm generally in a hardware-specific language, not Perl, so that one annoyance of Perl doesn't usually affect me. But there are a plethora in the hardware-specific language that I wish it did more like Perl does, so not a fair balance, in my opinion. :-( ) | [reply] [d/l] [select] |
|
c:\@Work\Perl\monks>perl -wMstrict -le
"use constant N_MAX => 10;
;;
my $nCond;
;;
CONDITION:
for ($nCond = 1; $nCond <= N_MAX; ++$nCond) {
print $nCond;
last CONDITION if $nCond >= 3;
}
;;
print qq{only made it to condition $nCond} if $nCond < N_MAX;
"
1
2
3
only made it to condition 3
(as suggested here)?
Give a man a fish: <%-{-{-{-<
| [reply] [d/l] [select] |
|
|
|
|
| [reply] [d/l] |
|
I find it odd that I don't remember ever suffering from this need. I'm sure I've done something similar, but perhaps I've unconsciously soaked up that lesson long ago, and just "know" to use a second variable, or even a while loop.
-QM
--
Quantum Mechanics: The dreams stuff is made of
| [reply] [d/l] |
|
$ perlcritic 1212245.pl
Loop iterator is not lexical at line 5, column 1. See page 108 of PBP
+. (Severity: 5)
| [reply] [d/l] |
Re: loop surprise
by ikegami (Patriarch) on Apr 04, 2018 at 15:25 UTC
|
local $e;
for $e (LIST) BLOCK
to
for $e (LIST) BLOCK
These days, it makes no sense to do anything but
for my $e (LIST) BLOCK
or
for (LIST) BLOCK
| [reply] [d/l] [select] |
Re: loop surprise
by karthiknix (Sexton) on Apr 05, 2018 at 10:28 UTC
|
My keyword is for local scoping of a variable. It says $i is a local variable, but it is global to the parent class.
$i you have used in for loop is local to for loop and it does not assign any value to it. You are iterating the loop for from 1 to 10 and it assign the value to a temporary variable in your case it is just $i. Below is an example how iterations works in a loop
for(1..10) {
print "yes" if(/7/);
}
in the above examples $_ is used a temporary variable and it gets null when it is out of for Loop. I hope it make you clear how Variables work in loop
| [reply] [d/l] |
Re: loop surprise
by Anonymous Monk on Apr 03, 2018 at 15:51 UTC
|
In any programming language, "loops are usually special." If you need to capture the value of a loop-control variable beyond the boundaries of the loop, use a separate variable for that purpose. (Remember to initialize it to some value before the loop begins, in case the loop doesn't run at all!) It is very common for various implementation quirks to be used with regard to loops, in the very-important name of efficiency. | [reply] |
|
It is very common for various implementation quirks to be used with regard to loops, in the very-important name of efficiency.
Rather than efficiency, I think reliability (or perhaps one should better say coherence) is the key concern. If a topicalized (i.e., localized and aliased) Perl-style loop iterator were left un-de-localized upon exit from the loop, to what would it be aliased? An arbitrary element of some named or referenced array? An item in a temporary list, perhaps a literal (i.e., something unwritable), or the (writeble) return value of a function call? (This point has been touched upon in other replies.) Such a state of affairs seems like a recipe for some very perplexing bugs.
IOW, if not de-localized, exactly what is the nature of the thing to which $_ would remain aliased after loop exit in this code:
c:\@Work\Perl\monks>perl -wMstrict -le
"sub F { return 4; }
sub G { return 5; }
sub H { return 6; }
;;
for (F(), G(), H()) { ++$_; printf qq{$_ }; }
"
5 6 7
And why would one want to do that?
Give a man a fish: <%-{-{-{-<
| [reply] [d/l] [select] |
|
if not de-localized, exactly what is the nature of the thing to which $_ would remain aliased after loop exit
Aliasing is an implicit reference to the object that is aliased. Like any referenced object, it would remain until all references to it have been removed.
As for why, to see what was last processed. Sure, you could use an extra variable, but doing so adds more opportunities for introducing bugs.
Besides, according to Larry, laziness is a virtue.
| [reply] |
|
|
| [reply] |
A reply falls below the community's threshold of quality. You may see it by logging in. |