Re^2: Scope and references
by {}think (Sexton) on Jun 19, 2011 at 16:52 UTC
|
Thanks. But that's what I don't get. Here's my confusion. I never realized that a simple loop like this (an even simpler illustration this time) ...
for (my $i=0; $i <=1; $i++){
my @a;
$a[$i] = 99;
print Dumper(\@a);
}
... which results in ...
$VAR1 = [
99
];
$VAR1 = [
undef,
99
];
...actually allocated and destroyed a new array every time through the loop. Since you go around the loop twice, it seems like you don't "leave" the scope in which @a was delcared, so @a should still "be there" during the second iteration. I still don't get that.
Also, I still don't understand why the 'wrong' version creates the data structure that it does. Any thoughts on that one?
{}think; #Think outside of the brackets
| [reply] [d/l] |
|
|
I never realized that a simple loop like this ... actually allocated and destroyed a new array every time through the loop. Since you go around the loop twice, it seems like you don't "leave" the scope in which @a was delcared, so @a should still "be there" during the second iteration. I still don't get that.
In for(...) { ... } the curly braces define a block. Each time the loop iterates you re-enter that block. And every time you enter a block, you enter a new scope.
That is just the way it is, and the way it is meant to be.
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] |
|
|
for (my $i=0; $i <=1; $i++) {
#new scope in brkts
}
I had always thought of the FOR loop as a single construct.
I didn't realize that each time the control logic ($i++, etc.) is exectuted, you EXIT the brackets and lose that scope! But if you parse the code very precisely, that is literally what happens, so it now makes sense! Thank you BrowserUk!
{}think; #Think outside of the brackets
| [reply] [d/l] |
|
|
So here was my misconception:
I thought that the scope of a for loop was
foreach (@a) { |<==From HERE to HERE==>| }
and that you
just bounced aroud INSIDE OF the brackets. But I guess every time you evaluated the control statement, you leave the brackets and you lose scope and re-enter it.
I did read Coping with Scoping, and that deals with this exact situation.
{}think; #Think outside of the brackets
| [reply] |
|
|
|
|
Actually, for creates two lexical scopes. One for the entire statement, and one of the block body.
You've already demonstrated the second. Here's a demonstration of the first:
>perl -e"use strict; for (my @x) { } @x"
Global symbol "@x" requires explicit package name at -e line 1.
Execution of -e aborted due to compilation errors.
it seems like you don't "leave" the scope in which @a was delcared,
It's pretty clear to me the curly is the end of the scope, and you do indeed reach it.
Also, I still don't understand why the 'wrong' version creates the data structure that it does. Any thoughts on that one?
my @a;
push @container, \@a;
push @container, \@a;
Isn't it clear that it puts two references to the same variable into @container? Why do you think your loop is different?
| [reply] [d/l] [select] |
|
|
Actually, for creates two lexical scopes. One for the entire statement, and one of the block body.
You've already demonstrated the second. Here's a demonstration of the first:
>perl -e"use strict; for (my @x) { } @x"
Global symbol "@x" requires explicit package name at -e line 1.
Execution of -e aborted due to compilation errors.
I don't think your example serves to prove your statement. Here's what I think is a better example:
use strict;
use warnings;
use 5.010;
for (my @x) {
my @x;
}
my @y;
my @y; #line 10
--output:--
"my" variable @y masks earlier declaration in same scope at perl.pl li
+ne 10.
| [reply] [d/l] [select] |
|
|
|
|
It might (or might not) be helpful to realize that my is an executable statement, not "just" a declaration.
update
The following is more misleading than helpful.
Please see the followup "puzzle" Re^4: Scope and references
to see why.
It produces a new instance of its argument(s),
effectively unrelated (except by name) to previous instances created in that scope, and any previous instance has its reference count reduced by 1. If you have tucked a reference to a previous instance into an array, as you did in your first example, that keeps the reference count positive, so the instance does not get garbage collected. If there is no other reference to a previous instance, it ceases to exist as far as you are concerned.
This isn't simple stuff, most of us have been tripped up by something similar when we first started using lexical variables.
| [reply] |
|
|
Here's a test of understanding. What does the following produce?
use strict;
use Data::Dumper;
my @array;
for (my $i = 0; $i < 5; ++$i) {
LABEL:
my @y;
push(@y, $i);
push(@array, \@y);
if ($i & 1) {
++$i;
goto LABEL;
}
}
print(Dumper(\@array), "\n");
Hint: I failed.
| [reply] [d/l] [select] |