some puzzles
Michael Fowler
michael at shoebox.net
Tue Mar 20 16:33:50 CST 2001
On Tue, Mar 20, 2001 at 11:40:58AM -0800, Rick J wrote:
> Thanks for the explanation on scoping, and great site
> http://perl.plover.com. I have read most of articles.
> I have a question about my scope as follow.
You're most welcome.
> use strict;
> my $count = 0;
> callsub() while ($count++ < 3);
> {
> my $num = 10;
> sub callsub {
> print ++$num, "\t";
> }
> print "$num\n";
> }
> It prints out 1 2 3 10.
>
> Is my understanding right? The first time when
> callsub() was called, the callsub was in the outer
> block where my $num was defined. So local $num was
> declared and defined, however, the process didn't
> reach the statement 'my $num = 10', so it did not get
> the defined value and printed as 1 2 3 respectively
> instead of 11 12 13. However, after the while loop was
> done, and this time, the program pass that statement,
> and got the value and printed it as 10.
You're dealing with two issues here. One is a closure, the other is
confusion about what happens when a subroutine is defined.
You should probably find a more robust description of clusures, but briefly
a closure is a subroutine that carries a set of lexical variables (defined
outside of the subroutine definition, but in the same scope) around with it.
The concept can be difficult to grasp; I will try to elaborate with your
code.
So the first thing you're seeing is the closure, callsub(), in action.
callsub() is defined in the same scope as the lexical $num, and it uses $num
in the body (of the subroutine), therefore it is a closure around $num.
$num has no value initially, because when you first call callsub() here:
callsub() while ($count++ < 3);
the "$num = 10;" line has not yet been encountered. callsub() increments
the lexical $num, which is effectively at 0, to 1. This is why you see the
sequence 1, 2, 3.
After that code, you enter the block:
{
my $num = 10;
sub callsub {
print ++$num, "\t";
}
print "$num\n";
}
$num is initialized to 10, and subsequently printed out. callsub() may be
defined here, but it is not actually called, so no increment takes place.
> I am still wondering why in the sub, it did not print
> 11 12 13. My here, looks more like local, because in
> that block, it stores 2 values for the my $num, one is
> 10, and the other is 1, 2, or 3. I am so clear and
> sure.
If you want to see the sequence 11, 12, 13 you have to initialize $num to 10
before calling callsub(). In your code you haven't done that.
What can be confusing is when statements are encountered. Recall I said the
initialization of $num wasn't encountered before the first call to
callsub(), but it's still a lexical variable. The reason is the my operator
has a compile-time effect, whereas assignment is done at runtime. So while
$num has been declared lexical, the code initializing it has not yet been
encountered by the time callsub() is first called.
> Another question is about assignment. I know that in
> assignment, if the right side is array, and left side
> is list or array, it just assigns the values
> accordingly. If the left side is scalar, it assigns
> the total number of elements in that array to the
> scalar variable. So the following cases indicate:
Here you seem to be confusing arrays and lists. An array in scalar context
yields the number of elements in the array; a list in scalar context yields
the last element of the list. The simple rule of thumb is that an array is
prefixed by the @ symbol, a list is not.
> 2. $var = (10, 20, 30); #$var is 30
(10, 20, 30) is a list.
> 3. my ($v1, $v2, @arr);
> $v1 = (($v2, @arr) = (10, 20, 30, 40));
> #$v1 is 4, $v2 is 10 and @arr has 20 30 40
This is a special case. A list assignemnt (that's the "($vw, @arr) ="
you're using) in scalar context yields the number of elements on the right
side of the assignment, much like an array, but it's still a list.
> 4. @arr = (10, 20, 30);
> $var = (@arr); #$var is 3
What you're seeing is a list of one element being evaluated in scalar
context, yielding the last element, @arr. @arr is then evaluated in scalar
context, yielding 3.
> 5. $var = 10, 20, 30; #$var is 10
This is simply a list of statements, where "$var = 10", "20", and "30" are
the individual statements. You would use such a thing in something like:
print("test passed"), $test_failed = 0, next if $test_passed;
Michael
--
Administrator www.shoebox.net
Programmer, System Administrator www.gallanttech.com
--
=================================================
Mailing list info: If at any time you wish to (un|re)subscribe to
the list send the request to majordomo at hfb.pm.org. All requests
should be in the body, and look like such
subscribe anchorage-pm-list
unsubscribe anchorage-pm-list
More information about the Anchorage-pm
mailing list