Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

What's a reference? What's a variable? What's scope?

by kurt_kober (Chaplain)
on Dec 28, 2002 at 18:42 UTC ( #222762=perlquestion: print w/replies, xml ) Need Help??

kurt_kober has asked for the wisdom of the Perl Monks concerning the following question:

I have a question about variable references. If one of you guys could answer I think it would clear up a lot of things in my brain about how Perl works. I've tried R'ing The FM, but it turns out I'm too stupid or the question is too simple.

My question is: why does this work?

use strict; my $hash_ref=&makehash; my %hash=%$hash_ref; print $hash{SQUEE}; exit; sub makehash { my %sub_hash; $sub_hash{SQUEE}="Nny"; return (\%sub_hash); }
Run this and it prints "Nny". I'm confused because I thought when using "strict", variables only existed inside their blocks, so that %sub_hash would only be accessible inside &makehash. When I pass the reference to %sub_hash back from &makehash, why isn't it a reference to something that no longer exists?

I know this is very basic but a lot of my mission-critical scripts pass references (and hashes of references, etc.) and I don't like the fact that fundamentally, I have no clue what's going on. What am I missing here?

Thanks,
Kurt

Replies are listed 'Best First'.
Re: What's a reference? What's a variable? What's scope?
by Juerd (Abbot) on Dec 28, 2002 at 19:36 UTC

    Perl uses a garbage collector. The technique for collecting garbage that Perl uses is called 'reference counting'.

    Every variable in Perl has a counter, the reference count. When the variable is created, the counter is set to 1. When the variable is referenced, it is increased by one.

    use strict; # 1 { # 2 my $foo = "Hello, world!\n"; # 3 print $foo; # 4 } # 5 print $foo; # 6
    Line 3: $foo is created, its reference count is now 1.
    Line 4: $foo is used for print, its reference count is increased. The reference count is now 2.
    Line 4: When print returns, the reference count is decreased. The reference count is now 1 again.
    Line 5: $foo's scope ends, the reference count is decreased. Because the reference count is 0 now, the variable is destroyed.
    Line 6: There is no $foo in this scope, and because the $foo in the block's scope no longer exists, there is no way to access it.

    use strict; # 1 my $bar; # 2 { # 3 my $foo = "Hello, world!\n"; # 4 print $foo; # 5 $bar = \$foo; # 6 } # 7 print $$bar; # 8
    Line 4: $foo is created, its reference count is now 1.
    Line 5: $foo is used for print, its reference count is increased. The reference count is now 2.
    Line 5: When print returns, the reference count is decreased. The reference count is now 1 again.
    Line 6: $bar is assigned a refence to $foo. $foo's reference count is now increased, and has a new value of 2.
    Line 7: $foo's scope ends, the reference count is decreased. Because the reference count is 1 (not 0, as in the previous example) now, the variable is not destroyed.
    Line 8: There is no $foo in this scope, but the variable that was called $foo in the block's scope can still be accessed through $bar. An extra $ is used to dereference it.

    Further reading:

    Additional nitpicking:

    • Don't use an & when calling a subroutine. If you do so without using parens, the current @_ is implicitly passed.
    • There's no need to exit() explicitly. If you want to make clear that no code follows, put your subs first (which has more advantages: your $hash_ref and %hash are shared throughout the program in the current situation - is that really what you want?)

    - Yes, I reinvent wheels.
    - Spam: Visit eurotraQ.
    

      Juerd++

      Nice explanation of reference counting.

      -- vek --
Re: What's a reference? What's a variable? What's scope?
by BrowserUk (Pope) on Dec 28, 2002 at 19:04 UTC

    In essence, %sub_hash comes into being at the line where you declare it with my. And, if you did not take a reference to it, it would "go out of scope", that is to say, the space allocated to it would no longer be addressable when the subroutine ended. At this point, perl would know that nothing could reference that space and may choose to reuse that space for some other purpose sometime later.

    However, as you have taken a reference to it and passed that reference back to an enclosing scope, (the calling program), perl has marked that peiced of storage as having been referenced and it therefore knows that it cannot reused that space until the variable holding the reference (and any other variables that it may have been assigned to) is itself no longer in scope at whatever level it was declared.

    So, when you return a reference to space allocated at one level of program scope, to an enclosing level of scope, allthough you can no longer refer to it by the original name, you can still refer to it's memory via the reference and let Perl take care of the nitty-gritty of if and when that space can be freed for reuse elsewhere.

    This comes as a strange concept if you have come from C or another language where you have to take care of allocating and deallocating storage yourself, but once you get used to it, it is an amazingly safe, powerful and useable concept.

    Read this Lexical scoping like a fox several times carefully, and the concept may start to clarify. Enjoy.


    Examine what is said, not who speaks.

      What you just encountered is called a closure.

      Uhm... No. It isn't. The rest of your explanation is pretty good though.

      A closure is created when you create an anonymous subroutine that has access to lexically scoped variables that are outside the sub's scope but are available at the time the sub is defined. It's hard to explain but easy to show via an example:

      my $counter = do { my $c; sub { $c++ } }; print &$counter, "\n" for 1..10;
      -sauoq
      "My two cents aren't worth a dime.";
      

        For the record, the quoted line was the first line of my post, for about 2 mins. I then withdrew it prior to seeing your reply.


        Examine what is said, not who speaks.

Re: What's a reference? What's a variable? What's scope?
by sauoq (Abbot) on Dec 28, 2002 at 19:07 UTC
    I'm confused because I thought when using "strict", variables only existed inside their blocks

    Using the strict pragma doesn't actually change where variables "exist" (as you put it.) What it does do is force the program to error out when a global variable is used without being properly declared. Variables declared with my are lexically scoped (not global) and are only visible to their enclosing block, file, or eval.

    When I pass the reference to %sub_hash back from &makehash, why isn't it a reference to something that no longer exists?

    It is probably easiest and most correct to think of the reference as a new value. It is also best to think of your variable's value and its name being separate. Your my %sub_hash variable is indeed only visible within your subroutine. That is to say, the value it holds can only be accessed via the name %sub_hash while inside your sub. If you did not pass a reference to the value back to the main program, there would be no way to get at that value again (and perl would consider it ripe for garbage collecting.) Since you do create a reference to the value by using the backwhack ("\") operator, perl makes a note of the fact that you still want it to be accessible (by incrementing its reference count) and will not garbage collect it.

    Does that help?

    -sauoq
    "My two cents aren't worth a dime.";
    
Re: What's a reference? What's a variable? What's scope?
by pg (Canon) on Dec 28, 2002 at 18:51 UTC
    That %sub_hash in your makehash function still "exists" (I said to myself, this is actually very VAGUE, what still exists? this can be interpreted in many ways, so...), or to be more precise, the memory allocated for it IS STILL ALLOCATED.

    As long as THERE IS STILL REF TO that piece of memory, INITIALLY being allocated under the NAME of %sub_hash, Perl/Perl's garbage collecting will NOT deallocate that piece of memory.

    Think about the "otherwise", otherwise you will have bunch of refs ref to memory spaces, which have been deallocated already. This breaks the PURPOSE of the programmer, in a normal case. Usually, the PURPOSE you return a ref, is that you still want to access whatever being ref'ed, why should Perl deallocate it? Perl is invented to SERVE your PURPOSE.
Re: What's a reference? What's a variable? What's scope?
by jk2addict (Chaplain) on Dec 28, 2002 at 20:20 UTC
    ...but it turns out I'm too stupid or the question is too simple.
    There is no such thing as a stupid question, only stupid computers. :-)
      There Are No Stupid Questions, But There Are A LOT Of Inquisitive Idiots.
      Cluelessness Poster from Despair, Inc.

      :-)

      Please note that this in no way reflects my opinion of the original post or its author.

      -sauoq
      "My two cents aren't worth a dime.";
      
        use strict; my $i_get_it_now; sub grateful { my $phrase_of_gratitude = qq/ Monks, I'm blown away by the quality of these answers. Thanks very much, I understand now--and I can sleep better. If only there was a perlmonks.org for every other aspect of life... Thanks, Kurt /; $i_get_it_now=\$phrase_of_gratitude; } grateful(); print $$i_get_it_now;

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://222762]
Approved by jeffa
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (3)
As of 2021-12-08 01:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    R or B?



    Results (34 votes). Check out past polls.

    Notices?