in reply to Re^5: Unable to declare local variable with "use strict".
in thread Unable to declare local variable with "use strict".

Generally, when people speak of a 'closure' in Perl, people mean a specific kind of subroutine, not a block, as your comment seems to indicate.

Closures are typically unnamed subroutines, holding a reference to their private instance of a variable (although such a variable may be shared between more than one subroutine). In your case, the subroutines are named, and there will only be once instance of $shared_variable.

Note also that your technique doesn't scale very well. Suppose you have subroutines sub1, sub2, sub3 and sub4. sub1 and sub2 want to share a variable $var1, sub2 and sub3 want to share a variable $var2, sub3 and sub4 want to share variable $var3, and sub4 and sub1 want to share $var4. In effect, you end up with all variables visible to all subroutines. An extra block doesn't really buy you much.

Replies are listed 'Best First'.
Re^7: Unable to declare local variable with "use strict".
by ikegami (Patriarch) on Mar 29, 2010 at 17:02 UTC

    Generally, when people speak of a 'closure' in Perl, people mean a specific kind of subroutine, not a block, as your comment seems to indicate.

    I wouldn't say it's generally not the block. I would say it's never the block. Besides that, I agree. The subs are closures, not the scope in which the variables reside.

    Closures are typically unnamed subroutines

    So?

    The code featured functions that captures a variable beyond it's normal scope. They are very much closures.

    It's really not that atypical either. It happens whenever you have module-level ("global") lexicals. The lexicals would normally fall out of scope when the module finished executing (i.e. before require returns), but they survive thanks to the methods that capture them.

    The only difference between named and unnamed subs is when the capture occurs. Named subs are instantiated at compile-time, so they capture at compile-time. Unnamed subs are instantiated at run-time, so they capture at run-time.

Re^7: Unable to declare local variable with "use strict".
by ikegami (Patriarch) on Mar 29, 2010 at 16:50 UTC

    [ Please ignore this post and read Re^7: Unable to declare local variable with "use strict". instead ]

    Are you saying he shouldn't call it a closure because (you say) it's not the general or typical example?

    The code featured functions that captures a variable beyond it's normal scope. They are very much closures.

    It's really not that atypical either. It happens whenever you have module-level lexicals. The lexicals would normally fall out of scope when the module finished executing when it's loaded, but they survive thanks to the methods that capture them.

    The only difference between named and unnamed subs is when the capture occurs. Named subs are instantiated at compile-time, so they capture at compile-time. Unnamed subs are instantiated at run-time, so they capture at run-time.

      Well, he's calling a block a closure - just look at where he claims the closure starts. I don't think that's a very typical use of the word 'closure' when it comes to Perl.
        Correct. I misunderstood your first paragraph. I posted a revised reply.
Re^7: Unable to declare local variable with "use strict".
by doug (Pilgrim) on Mar 29, 2010 at 17:31 UTC
    JavaFan wrote:
    Generally, when people speak of a 'closure' in Perl, people mean a specific kind of subroutine, not a block, as your comment seems to indicate.

    I disagree. Any block that creates scoped variables is a closure in my book.

    Note also that your technique doesn't scale very well. Suppose you have subroutines sub1, sub2, sub3 and sub4. sub1 and sub2 want to share a variable $var1, sub2 and sub3 want to share a variable $var2, sub3 and sub4 want to share variable $var3, and sub4 and sub1 want to share $var4. In effect, you end up with all variables visible to all subroutines. An extra block doesn't really buy you much.

    While you are absolutely right, who cares? Are you saying that everyone who creates a class has to build a potentially exhaustive set of classes and subclasses so that no one can see things that don't belong to them?

    Information hiding is a wonderful thing, but there is no need to go overboard with it. If you've got it down to where just a handful of localised subroutines (same closure) can get to the protected data, then you've done well enough.

    - doug

      Any block that creates scoped variables is a closure in my book.
      So, only blocks that don't create scoped variables aren't not closures? That's not a very useful definition. It's also a definition that's quite different from what other people use. Using your own definitions doesn't promote communication.

      Note that the important thing of what the rest of Perl world calls closures is the reference to lexical variables defined outside of the scope. The block rovf showed, and which you label a 'closure' doesn't reference a variable outside of its scope.

      Are you saying that everyone who creates a class has to build a potentially exhaustive set of classes and subclasses so that no one can see things that don't belong to them?
      Uhm, not at all. I commented on the technique rovf showed. I say it doesn't scale. What makes you think I promote that?

        The block rovf showed, and which you label a 'closure' doesn't reference a variable outside of its scope.

        The scope in which the variable exists ceases to exist long before the function was called. The function definitely references an out-of-scope variable.

        [ And JavaFan didn't say otherwise. Oops! ]

        $ perl -MO=Concise,foo,-exec -e'{ my $x; sub foo { $x } }' main::foo: 1 <;> nextstate(main 2 -e:1) v 2 <0> padsv[$x:FAKE:] <-- Is "FAKE": closed over 3 <1> leavesub[1 ref] K/REFC,1 -e syntax OK

        You seem to think nesting a named sub is the same as nesting blocks, but that's not the case at all. The scope of the outer block still exists when the the inner block is being executed.

        $ perl -MO=Concise,-exec -e'{ my $x; { $x } }' 1 <0> enter 2 <;> nextstate(main 4 -e:1) v:{ 3 <{> enterloop(next->b last->b redo->4) v 4 <;> nextstate(main 1 -e:1) v 5 <0> padsv[$x:1,3] vM/LVINTRO 6 <;> nextstate(main 3 -e:1) v 7 <{> enterloop(next->a last->a redo->8) v 8 <;> nextstate(main 2 -e:1) v 9 <0> padsv[$x:1,3] v <-- Not "FAKE": in scope a <2> leaveloop vK/2 b <2> leaveloop vK/2 c <@> leave[1 ref] vKP/REFC -e syntax OK
        I wrote:
        Any block that creates scoped variables is a closure in my book.
        And you replied:
        So, only blocks that don't create scoped variables aren't not closures? That's not a very useful definition. It's also a definition that's quite different from what other people use. Using your own definitions doesn't promote communication
        Note that the important thing of what the rest of Perl world calls closures is the reference to lexical variables defined outside of the scope. The block rovf showed, and which you label a 'closure' doesn't reference a variable outside of its scope.

        I must be missing something here. I don't remember replying to rofv. The thing I called a closure was introduced by me. It features two subroutines that, when called, access the variable $type, which has gone out of scope. Due to the closure formed by the anonymous block, $type remains, although it is only accessible via those two subroutines.

        Go re-read perlfaq7: It gives an example of using the BEGIN block do make a private variable just like I described. The section describing this in perlsub is called Persistent variables with closures.

        In perl there isn't really much of a difference between a subroutine and a block, so my use of closure includes either one. Any block is a potential closure in that it can potentially provide scope for a variable that will persist in a subroutine after the end of the block.

        I don't see why named blocks (subroutines) are given special status when the mechanism is more general than that. If the mechanism I showed is not a true closure, what would you call it? And how would you differentiate it from a closure via a subroutine?

        Googling for the term in various tutorials, I see your point that the first example is nearly always centered around subroutines, often with names like inner() and outer(). I think that is to make the examples easier to understand more than any particular desire to limit the term to subroutines.

        - doug

        PS: Yeah, I did screw up that definition. I left off the requirement that there has to be a way to get to those variables after the end of the scope of that block. Oops. Data without accessors just doesn't cut it. If that is the origin of this dispute, then I apologize for being unclear.