http://www.perlmonks.org?node_id=654763

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

Hi Monks, I know a lexical resides in its enclosed block, this is a definite closure
my $total_size =0; find{ sub $total_size += -s if -f}, '.'); print $total_size, "\n";
why this is not a closure though ?
use warnings; use strict; { my $a; } $a=1 print $a;
in my eyes my $a is visible outside the {} many thanks

Replies are listed 'Best First'.
Re: Closures clarification
by Corion (Patriarch) on Dec 04, 2007 at 13:04 UTC

    $a and $b are special variables and are exempt from use strict;. But the "outer" $a is different from your inner, lexical $a.

      Corion now i get the proper error as logic commands Thanks!!
Re: Closures clarification
by shmem (Chancellor) on Dec 04, 2007 at 13:33 UTC
    why this is not a closure though ?

    Because it is just a bare block. See perlsub and perlref, section Making References and the example there for how closures work.

    in my eyes my $a is visible outside the {} many thanks

    Outside the scope of that bare block, you see the global $a, which is special (see sort). How can you tell that it is the same as the $a declared with my inside the block? The inner is just declared and not used in any way. Here's how to check that:

    use warnings; use strict; $a=1; { my $a = 5; } print $a; __END__ 1

    One last thing - be sure that your example code actually compiles. Your first example doesn't, and in your second example there's a ';' missing at the end of $a=1

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Re: Closures clarification
by graff (Chancellor) on Dec 04, 2007 at 13:46 UTC
    why this is not a closure though ?
    use warnings; use strict; { my $a; } $a=1 print $a;
    in my eyes my $a is visible outside the {} many thanks

    First off, that's a bad example, because $a is a pre-defined global in perl, used by the built-in sort function. Secondly, when you declare a variable with "my", you are setting the scope of that variable to be the smallest block that encloses the declaration; or if it's not inside any curly-bracketed block, then the scope is the remainder of the given script file:

    use strict; use warnings; $x = 0; # syntax error: $x has not been declared my $y = 1; # ok, $y is "in scope" for remainder of file { my $y = 2; # a different $y, scope limited to this block print $y, $/; # you cannot "see" the "outer" instance of $y sub foo { $y--; print "the inner \$y is now $y\n"; } foo(); } print $y, $/; # this is the "outer" $y my $x = 3; # ok: $x is in scope for remainder of file my $y = 4; # warning: "my" declaration masks earlier declaration in +same scope print $y,$/; foo();
    As-is, that snippet will not run, but it will generate the error and warning messages shown in comments. Delete or comment-out the "$x=0" line, and it will run, but the "my $y=4" will still cause the warning about "masks earlier declaration in same scope".

    When it runs, you'll see that the sub "foo", which is callable from anywhere, will always use the "inner" instance of $y, because that's the only one it could "see".

    (updated to remove a stray ";", and to make the "foo" sub a little more interesting)

Re: Closures clarification
by moritz (Cardinal) on Dec 04, 2007 at 12:46 UTC
    First of all a closure is a subroutine, and your second example doesn't include one.

    Secondly in a closure you have access to a variable in an outer scope, which is "enclosed" in the sub (hence the name), in your first example $total_size.

Re: Closures clarification
by memnoch (Scribe) on Dec 04, 2007 at 14:03 UTC
    If I'm not mistaken, neither of your examples are closures. According to Intermediate Perl, a closure is "just a subroutine that references a lexical variable that has gone out of scope".

    In your first example, while there is an anonymous subroutine reference passed to the find() function, it doesn't reference any lexical variables. In your second example, 1) there is no subroutine, and 2) the $a enclosed in braces is a different variable than the one outside of them.

    Note also that your first example was incorrect. It should have been:

    use File::Find; my $total_size = 0; find(sub {$total_size += -s if -f}, '.'); print $total_size, "\n";
    You were missing the "use" statement, missing a "(" in the find function, and the "{" in the sub definition was misplaced.

    An example of a closure from Intermediate Perl) is as follows:
    use File::Find; my $callback; { my $count = 0; $callback = sub { print ++$count, ":$File::Find::name\n" }; } find($callback, '.');
    So, here the subroutine is a closure because it refers to the lexical variable $count.

    Hope this helps.

    memnoch

    Gloria in Excelsis Deo!

      If I'm not mistaken, neither of your examples are closures. According to Intermediate Perl, a closure is "just a subroutine that references a lexical variable that has gone out of scope".

      The anonymous subroutine passed by reference to find does bind a lexical variable ($total_size). By most definitions (e.g wikipedia's), that subroutine is then a closure. The variable doesn't have to have gone out of lexical scope. The important part is that the subroutine deeply binds the variable, and the variable may go out of scope.

      lodin

      PS. The code should read sub { instead of { sub, but that's not important for the question at hand.

        Thanks lodin...I missed that other typo! I have addressed it in my previous posting. But as far as whether it was a closure or not, according to Intermediate Perl, the lexical variable needs to have gone out of scope for the subroutine to be a closure....that's what I was going off of.

        memnoch

        Gloria in Excelsis Deo!
      And what else is he missing?
      use File::Find; my $total_size = 0; find({sub $total_size += -s if -f}, '.'); print $total_size, "\n";
      You were missing the "use" statement and a "(" in the find function.
        Thanks fenLisesi....I missed that other typo...I have fixed it in my original posting as well.

        memnoch

        Gloria in Excelsis Deo!
Re: Closures clarification
by fenLisesi (Priest) on Dec 04, 2007 at 13:00 UTC
    I don't even get the first one:
    this is a definite closure
    my $total_size =0; find{ sub $total_size += -s if -f}, '.'); print $total_size, "\n";
    What are you trying to do there?
      props,

      Studying the examples in a good book is a great way to learn, but you need to run the examples and play with them a little. I don't have that book, but it is unlikely that the code you posted would come from there. Why don't you go ahead now and run that code first and tell us how you think it works (or doesn't)? Then monks will be able discuss it with you. Cheers.

        I really dislike downvoting (which I just did) on nodes expressing opinion; the more so, in this case, because all but fenLisesi's second sentence have merit (IMO). My error!

        Update: The above was well intentioned, but bleary-eyed /me carelessly missed the typo in prop's OP, in which

        find{ sub $total_size += -s if -f}, '.');
            should be
        find (sub { $total_size += -s if -f}, '.');.

        mea culpa and apologies.

        But sentence 2 amount to a direct and gratuitous negative implication about props' integrity (or, I suppose, ability to copy code from a book)... and it is wrong.

        The intial code fragment comes from p71 of Intermediate Perl, 2nd edition. It is verbatim, save for the book's inclusion of a use File::Find above. And it's available, on line, for your ease of checking these assertions, at http://safari.oreilly.com/ (more precisely, and as a link, 7.4 . Closures)

      This is an example from "Intermediate Perl" aims to demonstrate the presence of a closure
        It is a closure, you want to pass in a bit of code into a function(perldoc -q closure)