Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

(tye)Re: Unusual Closure Behaviour

by tye (Cardinal)
on Jul 12, 2001 at 14:27 UTC ( #95971=note: print w/ replies, xml ) Need Help??


in reply to Unusual Closure Behaviour

First, neither of those are closures. They are both examples of static variables and named functions. The term "closure" refers to a code reference that also carries along some variables. In neither of these case is the $x being carried around in a code reference (in part because no code references are being used).

Second, I (if anyone cares) don't consider my $x if 0; to be a good thing to actually use. A while back I had an idea to allow BEGIN to be a statement modifier just like for, while, if, etc. Then you could implement static variables like:

sub foo { my $x= 'a' BEGIN; return ++$x; }
which has the benefit of allowing you to initialize your static vars and of cluing you into the fact that the initialization happens at compile time so you can't use anything that isn't available yet.

This feature would have other nifty uses. For example: my $haveCGI= eval { require CGI }   BEGIN;
But the one that could be really fun would be: eval "my $ARGV[0];"   BEGIN;
if you could stop eval from implying an enclosing scope. This could be very powerful and give TheDamian lots of new ways to do really scary things in Perl. (:

        - tye (but my friends call me "Tye")


Comment on (tye)Re: Unusual Closure Behaviour
Select or Download Code
A Real Closure
by japhy (Canon) on Jul 12, 2001 at 16:03 UTC
    A while back I'd talked to Randal about closures, and he told me that a closure needn't be a code reference:
    >>>>> "Jeff" == Jeff Pinyan <jeffp@crusoe.net> writes: Jeff> A closure is an ANONYMOUS function (constructed via $x = sub { Jeff> ... }) that contains LEXICAL variables that have been defined in Jeff> a scope visible to the closure itself. leave out the word ANONYMOUS there. ANONYMOUS and CLOSURE are orthogonal. in "BEGIN { my $x; sub foo { ... $x ... } }", foo is a CLOSURE and is not ANONYMOUS.


    japhy -- Perl and Regex Hacker
      The docs are pretty clear that using sub to create a ref to an anonomous sub will do closures and that a normal named sub will not.

      So I tried it. It gives me a warning that "$x will not stay shared", but the result seems to work! That is, a created named function seems to reference the same variable as a standard closure created in the same scope, and running the creator again (which makes a different local $x) keeps distinct identities.

      So what's going on here? Are the docs outdated? Is this working by accident or happenstance? Does the presence of a regular closure somehow make it work?

      —John

      use v5.6.1; # Active State build 626 use strict; use warnings; sub outer { my $x= shift; my $name= shift; my $closure= sub { return $x++; }; eval "sub $name { return \$x++; }"; return $closure; } my $r1= outer (1, 'f1'); my $r2= \&f1; print $r1->(), $r2->(), "\n"; my $r3= outer ('A', 'f2'); my $r4= \&f2; print $r3->(), $r4->(),$r3->(), $r4->(), "\n"; print $r1->(), $r2->(),$r1->(), $r2->(), "\n";
        Err, the warning is due to defining a function (that ends up acting as a closure, due to its use of lexicals defined in an upper scope) inside a function. But if you write:
        { my $x; sub count { ++$x } }
        Then $x is private to &count, and because &count refers to a lexical that "should" have "gone away", it is a closure. At least, that is what I have understood from Randal.

        japhy -- Perl and Regex Hacker

      That is an interesting case BEGIN { my $x; sub foo { ... $x ... } }
      Perl could decide to implement that as a closure (and probably does because "BEGIN" blocks are implemented as subroutines). But lets find out:

      #!/usr/bin/perl -w use strict; use Devel::Peek qw(Dump); BEGIN { my $x; sub begin { ++$x; } } sub justmy { my $x; ++$x; } sub ifmy { my $x if 0; ++$x; } { my $x; sub static { ++$x; } } sub nest { my $x; sub inner { ++$x } } sub gen { my $x; return sub { ++$x }; } *insert= gen(); Dump $_ for( \&begin, \&justmy, \&ifmy, \&static, \&inner, gen(), \&insert + );
      The "cleaned up" output is:
      Variable "$x" will not stay shared at closure.pl line 27. begin: SV = RV(0x1a83a20) at 0x1a65068 SV = PVCV(0x1a8340c) at 0x1a62144 GVGV::GV = 0x1a7b6c0 "main" :: "begin" PADLIST = 0x1a7b690 1. 0x1a621b0 (FAKE "$x" 0-57) OUTSIDE = 0x1a620fc (UNIQUE) justmy: SV = RV(0x1a83a2c) at 0x1a65098 SV = PVCV(0x1a8345c) at 0x1a620f0 GVGV::GV = 0x1a7b72c "main" :: "justmy" PADLIST = 0x1a7b708 1. 0x1a7b714 ("$x" 59-60) OUTSIDE = 0x1a6f124 (MAIN) ifmy: SV = RV(0x1a83a30) at 0x1a650b0 SV = PVCV(0x1a7adbc) at 0x1a7b750 GVGV::GV = 0x1a7b798 "main" :: "ifmy" PADLIST = 0x1a7b774 1. 0x1a7b780 ("$x" 61-62) OUTSIDE = 0x1a6f124 (MAIN) static: SV = RV(0x1a839dc) at 0x1a650e0 SV = PVCV(0x1a7ada4) at 0x1a7b76c GVGV::GV = 0x1a7b7a8 "main" :: "static" PADLIST = 0x1a7b790 1. 0x1a620f0 (FAKE "$x" 0-64) OUTSIDE = 0x1a6f124 (MAIN) inner: SV = RV(0x1a83a34) at 0x1a650c8 SV = PVCV(0x1a7ae5c) at 0x1a7b81c GVGV::GV = 0x1a7b858 "main" :: "inner" PADLIST = 0x1a7b840 1. 0x1a7b7ec (FAKE "$x" 0-64) OUTSIDE = 0x1a7b7bc (nest) gen(): SV = RV(0x1a83a38) at 0x1a65158 SV = PVCV(0x1a7af9c) at 0x1a650e0 FLAGS = (ANON,CLONED) GVGV::GV = 0x1a7b924 "main" :: "__ANON__" PADLIST = 0x1a65128 1. 0x1a65080 (FAKE "$x" 0-67) OUTSIDE = 0x1a7b894 (gen) SV = PVCV(0x1a7aeac) at 0x1a7b894 GVGV::GV = 0x1a7b93c "main" :: "gen" PADLIST = 0x1a7b8b8 1. 0x1a65170 ("$x" 66-68) 2. 0x1a7b8e8 ("&" 1--1) OUTSIDE = 0x1a6f124 (MAIN) insert: SV = RV(0x1a83a3c) at 0x1a65188 SV = PVCV(0x1a7af4c) at 0x1a6f01c FLAGS = (ANON,CLONED) GVGV::GV = 0x1a7b924 "main" :: "__ANON__" FLAGS = 0x6 PADLIST = 0x1a6f0f4 1. 0x1a7b8c4 (FAKE "$x" 0-67) OUTSIDE = 0x1a7b894 (gen) SV = PVCV(0x1a7aeac) at 0x1a7b894 GVGV::GV = 0x1a7b93c "main" :: "gen" PADLIST = 0x1a7b8b8 1. 0x1a65170 ("$x" 66-68) 2. 0x1a7b8e8 ("&" 1--1) OUTSIDE = 0x1a6f124 (MAIN)
      or just consider
      begin: 1. 0x1a621b0 (FAKE "$x" 0-57) justmy: 1. 0x1a7b714 ("$x" 59-60) ifmy: 1. 0x1a7b780 ("$x" 61-62) static: 1. 0x1a620f0 (FAKE "$x" 0-64) inner: 1. 0x1a7b7ec (FAKE "$x" 0-64) gen(): 1. 0x1a65080 (FAKE "$x" 0-67) insert: 1. 0x1a7b8c4 (FAKE "$x" 0-67)
      which seems to indicates that "justmy" and "ifmy" are not implemented as closures but all of the rest are implemented as closures. So I'll certainly be more lenient in what I let other people call closures. (:

      But it also indicates that the padlist is carried around for ordinary subroutines, which makes that aspect of the implementation less important to me.

      I think that the important thing about closures is being able to call the same code but have it use different variables (without passing them in as arguments). Above, only the anonymous subroutine and "insert" meet that criterion. So those are what I'll call closures. The other 3 cases I'll call "static variables that Perl implements via closures" if pushed. :)

              - tye (but my friends call me "Tye")
        I think that the important thing about closures is being able to call the same code but have it use different variables (without passing them in as arguments). Above, only the anonymous subroutine and "insert" meet that criterion. So those are what I'll call closures.

        What do you mean by this? I think I'm missing something when it comes to closures...

        I think that the important thing about closures is being able to call the same code but have it use different variables (without passing them in as arguments).

        No. You are just confusing a useful use of closures for a definition of what they are.

        A closure is simply a function that refers to a free lexical variable. In the code { my $x=0; sub foo { $x } }
        foo() is a closure; it just isn't a very useful one. In Perl, named closures are good for simulating static variables, but not much else (that I can think of.)

        -sauoq
        "My two cents aren't worth a dime.";
        
Re: (tye)Re: Unusual Closure Behaviour
by suaveant (Parson) on Jul 12, 2001 at 17:51 UTC
    his first example
    { my $x; sub foo { return ++$x; } }
    is very much a closure, because $x is lexically scoped to that block, and sub foo is by definition global and survives the loop, $x goes away, except for the one reference in sub foo. his second one, however, would not be a closure.

                    - Ant

Re: Unusual Closure Behaviour
by Dominus (Parson) on Jul 14, 2001 at 07:08 UTC
    Says tye:
    First, neither of those are closures. They are both examples of static variables and named functions. The term "closure" refers to a code reference that also carries along some variables. In neither of these case is the $x being carried around in a code reference (in part because no code references are being used).
    There is indeed code reference. It is stored in the symbol table for the main package. It points to a CV, just like any other code reference, and the CV has a pointer to the pad, which does have the $x variable captured in it, just like any other closure.

    So yes, it is a closure.

    --
    Mark Dominus
    Perl Paraphernalia

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (9)
As of 2014-10-31 10:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (216 votes), past polls