Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Re: typeglobs and filehandles

by Dominus (Parson)
on Dec 20, 2000 at 23:15 UTC ( #47633=note: print w/ replies, xml ) Need Help??


in reply to typeglobs and filehandles

Says zzspectrez:

> Im confused on how the block can return the value
> of *FH which loses scope once the block exits.
I'm going to explain this in two ways. First, I'll show an analogy to something that you probably do all the time:
sub foo { my $z = 4; return $z; }
How can the block return the value of $z which loses scope once the block exits? But there's no problem here, and you probably never thought that there might be a problem. So why are you worried about returning the value of *FH in the same way?

Second explanation: You have misunderstood the notion of scope. Values don't have scope. Variables don't have scope. Only names have scope.

In the code { my $var; ... }, the name var is in scope inside the block. Outside the block, it is out of scope, and the name has no meaning.

Does the variable lose its value just because the name has gone out of scope? Maybe, but maybe not. Consider this:

my $x; { my $var = 4; $x = \$var; } # 'var' is now out of scope. print $$x; # but this still prints "4".

Here we create a variable, named $var, and set it to 4. Then we take a reference to the variable and store the reference in $x. Then the name var goes out of scope.

Is the variable destroyed? No. Why not? Because in Perl, a variable is never destroyed just because its name has gone out of scope. In Perl, a variable is destroyed when there are no references to it. The name is one reference. Usually it's the only one, and when the name goes away, there are no more references, and the variable is destroyed. In this case, there is a second reference, in $x, so the variable that was formerly known as $var will not be destroyed until the reference in $x is also gone. It's not known as $var any more (because that name is out of scope) but it's not destroyed either.

Scope is the part of the program text in which the name is visible. It's independent of what happens when the program is run. You can tell just from looking at the source code what the scope of each name is. In Perl, the scope of a name begins on the statement following the declaration, and continues up to the end of the smallest enclosing block.

Variables do not have scope. Instead, they have duration. The duration of a variable is the period of time in which memory is allocated for the variable. In Perl, a variable's duration continues until there are no more references to it, at which point it is destroyed.

People often confuse variables with their names, but they are not the same thing. A variable is a part of the computer's memory, and it might or might not have a name. In a program, the same name might refer to different variables at different times.


Now what is my $x = do { local *FH }; doing?

I'm going to remove one of the confusions by rewriting it in an equivalent form:

sub new_filehandle { local *FH; return *FH; } $x = new_filehandle();

What does new_filehandle do? First, it removes the old value that *FH had, if any, and replaces the value of *FH with a new, fresh glob. It arranges for the old value of *FH to be restored at the end of the block.

Then it returns the value of *FH, which as we just saw, is a new, fresh glob. That new, fresh glob is what is assigned to $x.

Then it's the end of the block, so the old value of *FH is restored.

Is the new, fresh glob destroyed? No. Why not? Its duration (not scope) is still going on, because it is referenced by $x.

Now you probably know that return is optional on the last line of a subroutine; Perl will return the final value whether you say return or not. That's why you can write sub pi { 3.14159 }. So we can get rid of return:

sub new_filehandle { local *FH; *FH; # 'return' is implied } $x = new_filehandle();

It turns out that the value of the local is the new value of *FH, so it is not necessary to repeat *FH:

sub new_filehandle { local *FH; # return of *FH is implied } $x = new_filehandle();

Now we can replace the subroutine with a do block, which just executes the code in a block and returns the resulting value:

$x = do { local *FH; }; # return of *FH is implied

Hope this helps.


Comment on Re: typeglobs and filehandles
Select or Download Code
Re: Re: typeglobs and filehandles
by fundflow (Chaplain) on Dec 20, 2000 at 23:27 UTC
    >Hope this helps.

    It helps alot!

    As an occasional perl programmer, i'd like to thank you for this reply. I was not aware of these subtleties.

(Dermot) Re: Re: typeglobs and filehandles
by Dermot (Scribe) on Dec 20, 2000 at 23:41 UTC
    This is a really excellent explanation. Thank you very much. It can be tricky to keep track of names, scopes and durations while programming but it is certainly harder when you don't even fully understand what the various concepts represent.

    Maybe even worth putting somewhere like the tutorials section?

Re: Re: typeglobs and filehandles
by Trimbach (Curate) on Dec 20, 2000 at 23:44 UTC
    This post was so good I am moved to comment on it directly... ++ simply isn't enough.

    Wow. You rock.

    Gary Blackburn
    Trained Killer

Re: Re: typeglobs and filehandles
by ambiguous (Novice) on Dec 21, 2000 at 02:52 UTC
    I am one step closer to enlightenment for having read this.
Re: Re: typeglobs and filehandles
by snax (Friar) on Dec 21, 2000 at 07:13 UTC
    Sez Dominus:
    > Values don't have scope. Variables don't have scope.
    > Only names have scope.

    See, things like this are why I like to hang out here.

    Simple. Straightforward. Enlightening. It's a hat trick!

    Well done, and thanks in general. This (the whole post) should be in a tutorial.

Re: Re: typeglobs and filehandles
by zzspectrez (Hermit) on Dec 21, 2000 at 12:51 UTC

    Let me start off by saying thank you for such a well written response! You have clarified and verified my understanding of a lot of whats going on.

    Dominus says:
    > Variables do not have scope. Instead, they have duration.
    >The duration of a variable is the period of time in which
    >memory is allocated for the variable. In Perl, a variable's
    >duration continues until there are no more references to it, at
    >which point it is destroyed.

    This makes sense. Perl doesnt dispose of a variables value in memory untill there are no more references to it. This seems to be convenient. However.. I was wondering if this could cause problems in the situation of say a Linked List. Since the list would have references to other nodes in the list, you would think you would have to traverse the structure to release the memory. So of course I made another test:

    #!/usr/bin/perl -w sub add_node { my $tmp = { }; my $prev = shift; $tmp->{'prev'} = $prev; $tmp->{'data'} = shift; $prev->{'next'} = $tmp; return $tmp; } my $pos = { data => 0 }; { my $cur = $pos; for my $x (1..1000000) { $cur = add_node($cur, $x); } } while ($inp ne "quit") { print "DATA: $pos->{'data'}\n"; $inp = <STDIN>; chomp $inp; if ($inp eq '>') { $pos = $pos->{'next'} if exists ($pos->{'next'}); }elsif ($inp eq '<') { $pos = $pos->{'prev'} if exists ($pos->{'prev'}); } } sleep (10); print "\$pos = undef\n"; $pos = undef; sleep (10); $pos = "zzSPECTREz"; print "\$pos = $pos\n"; sleep (10); print "make new linked list with \$pos\n"; { my $cur = $pos; for my $x (1..100000) { $cur = add_node($cur, $x); } } sleep(10);

    Now I open Windows Task Manager to watch memory usage of perl with this script. As the script builds the list perls memory usage grows significantly and settles at 68,820k. Using the '<' and '>' keys I navigate the list verify it works. Then type quit. First the $pos variable is set to undef. No change in memory usage. Then it is set to the text 'zzSPECTREz' no memory change. Then we build a new smaller linked list. At this point the memory usage shrinks to about 12,400k. Hmmm.

    This leaves me confused on whats happening. I thought that a memory leak would be caused since I was destroying my reference to my linked list but since the list had references to itself perl would not release the memory. This would make sense. The test program seems to prove this when memory is not released when I change the value of my pointer to my list. However the memory does release when I build a new list using that variable.. Why?

    thank you for your explanations!
    zzSPECTREz

      Perl has a "leak" with circular references. I sort of boggled at your code for a while since it is rather, *ahem* pathological, but in the end I don't think you made a circular construct. You just made a really deep set of nested hashes. I think the whole thing can unwind from the top. The reference you destroy is the lynchpin and once it is pulled each remaining level can fall one by one.
      # These are bad, um-kay? my $a; $a = \$a; my ($b,$c); ($b, $c) = \($c, $b); my @d; $d[0]=0; $d[$_]=\$d[$_-1] for (1..100_000); $d[0]=\$d[$#d];

      --
      $you = new YOU;
      honk() if $you->love(perl)

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://47633]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (6)
As of 2014-09-22 07:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (182 votes), past polls