in reply to Catching closures

Could you tell me more about problems you see with closures? I use them quite liberally and haven't had any problems. Should I be more careful?

Replies are listed 'Best First'.
Re^2: Catching closures
by CountZero (Bishop) on Mar 05, 2008 at 21:40 UTC
    What the OP is refering to is the fact that under mod_perl your ordinary code get turned into a subroutine (if it is run as a registry script that is) and all of a sudden the subroutines in your code will unexpectedly close over lexical variables defined outside of their scope. This gives all kinds of strange effects such as your webpages "remembering" previous values and not resetting them.

    Closures are not bad, but if they happen unexpectedly they are quite bothersome and difficult to debug.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

      Except that those types of closures are easy to find if you have warnings turned on.
        That is indeed the advice the mod_perl book gives.

        CountZero

        A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

      If the OP is referring to that, he should just use warnings and look at the error log, instead of trying to prevent all the useful uses of closures.

      For the record, I intentionally use closures in a mod_perl environment all the time, and as far as I can see there aren't any more problems with closures than with other "complex" use of references.

        I'm concerned about things like putting the Apache::Request object into a closure, and getting issues like this : Calls to Apache::Request's param method sometimes end the program and return no data.

        And generally, if any other variables persist from request to request just because I used them in a closure, that would be annoying. (Of course, sometimes I want things to persist, and closures are helpful, but I don't do that in the context of calling a method for doing a database transaction).

        e.g. I wanted to avoid doing this :
        my $object; do_transaction(code => sub {....$object->update..})

        On second though, maybe the above is okay, since once the anonymous sub goes away, the reference to $object does too, so maybe I'm being unnecessarily cautious.
        "intentionally" being the operative word here!

        I guess the OP does not use closures in his code and wants to guard against the unexpected ones.

        CountZero

        A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re^2: Catching closures
by hipowls (Curate) on Mar 05, 2008 at 21:03 UTC

    I also don't see the problem. If the subroutine refers to lexicals in the enclosing scope and modifies them, no harm is done since it gets its own copy of the lexicals

    You could equally well say that assignment can have bad effects and be hard to track down.

      Well, technically it doesn't get its own copy, it shares its copy with stuff declared in the same scope:

      use strict; use warnings; sub funcs { my $a = 0; return ( sub { $a++ }, sub { $a } ); } my ( $f11, $f12 ) = funcs(); my ( $f21, $f22 ) = funcs(); print join( " ", $f11->(), $f12->(), $f22->() ), "\n"; #prints "0 1 0"

      My point was that if someone wants to change state, he should understand what he's doing. And he probably does. Preventing that is rude.

      The OP may be in some special situation, however. That's what my question was about.

        I guess to be really pedantic that should be it shares a copy with stuff declared in the same scope at the same time.but functions declared on entering the same scope later get their own set of shared variables. I take your point though and stand corrected.

        I read CountZero's reply and I now understand the OP's concern but I don't see that debugging a variable that has leaked into a closure is any harder than debugging the same problem with regular functions.

        my $var; sub the_first { $var = func1(); } # many, many lines of code later sub the_second { $var = disfunction(); }
        and in most cases the closures are declared together so it is probably easier to spot.

        I think the answer is to be careful with variables, restricting them to as small a scope as possible and to have as few as possible with file scope.