I'm writing this because I lost about 1-2 hours to debug a problem which was caused by closures.

Suppose you have a method of a class that you write using Moose(but a plain Perl object is also relevant), and you use inside that method a static variable (static in the C sense, by that I mean a variable that has scope local to the method but a lifetime that spans each call of said method). I was recommended that I use a closure and enclose the declaration of that variable and the method inside the closure to cause the variable to be static(again, the C sense of static).

What happened, was that when I created 2 objects, the value of that static variable wasn't really resetted, so most of my tests started failing, so of course the next natural move(after debugging for 1-2 hours) was to either

I chose the latter.

Please notice that the former would attract another problem: suppose you were doing this not inside a class, but inside a role, which does not define the ctor/dtor , so now you can't reset it in the ctor/dtor because that is not specific to the role, it's specific to classes consuming that role.

I suspect there are at least 2 plausible reasons for this :

I will be cautious not to draw any conclusions from this, instead, I'd like your oppinion on closures and their side-effects.

Replies are listed 'Best First'.
Re: Some trouble with closures
by moritz (Cardinal) on Feb 17, 2010 at 09:18 UTC
    I'm a bit confused by your confusion.

    If you want to store data that's not shared between different instances (objects) of the same class, an attribute is what you need, and what attributes are there for.

    Your description that you don't want the variable shared between various objects indicates that a static variable (emulated by a lexical variable from an outer scope, or implemented by a state variable) is specifically not what you need.

    I can recommend a very good book to you: Bertrand Meyer, Object-Oriented Software Construction. If you read that from cover to cover, I can guarantee that you won't confuse attributes with anything else afterwards.

    closures cause various side-effects not immediately noticeable that lead to bugs

    Every construct leads to bugs when used in a context where it's not appropriate.

    Perl 6 - links to (nearly) everything that is Perl 6.

      I second moritz. You've created a persistent state variable -- a static variable in your terms -- a variable local to the class, not to the instance. Therefore, it's not reset on object creation, which is exactly what you want if you want a persistent state.

      You probably don't want that, if you want it to be reset for each object; you just want an ordinary attribute -- a variable local to the instance. The traditional choice is to declare the object in the constructor as a reference to a blessed hash and store your data within the hash. There are other ways to do it, of course.

      Um, by the way, if you do decide to create a persistent state variable, you might want to enclose the entire class in braces, rather than only one method:

      If you do THIS, then when you $bar = Foo::new(); and later $bar->fiddle() or $bar->fuddle() it, you will still have access within those methods to $state. If you don't, and do THAT (as you described), then you will have created a state variable peculiar to the method faddle(), invisible even to other methods of the same class. Are you sure y/N?

Re: Some trouble with closures
by chromatic (Archbishop) on Feb 17, 2010 at 06:32 UTC

    I'm not sure anyone can answer your question without seeing your code and your explanation of what you're trying to do. From what I can gather, the closure is working exactly as designed. If you find yourself trying to reset the value of a closed-over lexical from an object constructor, you're in for a world of pain. Use an object attribute for object-specific data.

Re: Some trouble with closures
by WizardOfUz (Friar) on Feb 17, 2010 at 08:03 UTC
Re: Some trouble with closures
by doug (Pilgrim) on Feb 17, 2010 at 14:27 UTC
    Suppose you have a method of a class that you write using Moose(but a plain Perl object is also relevant), and you use inside that method a static variable (static in the C sense, by that I mean a variable that has scope local to the method but a lifetime that spans each call of said method). I was recommended that I use a closure and enclose the declaration of that variable and the method inside the closure to cause the variable to be static(again, the C sense of static).

    Mixing C-think and Perl-think is not always a good idea. What you are looking for is a state variable, and that is a feature that is new with 5.10 and has to be requested. No closure is required.

    Pre-5.10 you do this with a closure.

    { # open an anonymous block to form the closure my $foo; my $bar; sub fubar { # code that uses $foo and $bar # goes in here } } # end of the closure

    At the end of the closure the two variables go out of scope, but subsequent calls to fubar() still can use them without a problem.

    - doug

Re: Some trouble with closures
by JavaFan (Canon) on Feb 17, 2010 at 12:32 UTC
    Suppose you have a method of a class that you write using Moose(but a plain Perl object is also relevant), and you use inside that method a static variable (static in the C sense, by that I mean a variable that has scope local to the method but a lifetime that spans each call of said method). I was recommended that I use a closure and enclose the declaration of that variable and the method inside the closure to cause the variable to be static(again, the C sense of static).
    My recommendation would be to declare the variable with the static keyword inside the sub you want to static variable.
    give up the closure and the static(in C sense) variable and go for an attribute in the class that would be used for this, which if you use Moose has the advantage of being able to specify default => value , so the attribute is set to that value upon constructing a new object
    Huh? What? Now I'm confused. Do you want a static variable, or not? If it's static (as in the C sense; and in the Perl sense), there's just one. If you want a different one per object, you don't have static variables; you have your classic, run-of-the-mill, 14-in-a-dozen, object attribute. But C doesn't have objects, so if it's "in the C sense", it cannot be related to objects, can it?

    Perhaps you should explain what you want this variable to be.

      My recommendation would be to declare the variable with the static keyword inside the sub you want to static variable.

      Perl 5.8.x is still the default perl for most OS's at this point. I'd recommend that someone know both ways, but unless they can be sure their project is going to be running on the latest version of perl, I'd use the slightly clunkier style. Synatic sugar is nice, but having a working program is better.

      Of course, the point that they should know whether they actually want a static variable or not is right on.

        Perl 5.8.x is still the default perl for most OS's at this point.
        I don't get this argument. We always tell people to download the whole world from CPAN, even offering how to use modules if you can't install them the place your sysadmin does.

        But going to CPAN and getting perl itself is somehow a big NoNo?

Re: Some trouble with closures
by TGI (Parson) on Feb 19, 2010 at 00:06 UTC

    Can you expand on what you were trying to accomplish with your variable?

    Typically, you have two types of data associated with a class: class data and object data. Object data is unique for each object, and is properly stored in attributes. Class data is shared between all objects that are in the class.

    Here's a very simple classical Perl OO class with both class and object data.

    package MyClass; my $instances = 0; # Class data as a lexical sub new { my $class = shift; my $self = { attribute => 'foo', }; bless $self, $class; $instances++; return $self; } sub DESTROY { my $self = shift; $instances--; return; } # Class data accessor # Could also be a mutator, but it doesn't makes sense here. sub instances { return $instances; } # Class data accessor/mutator sub attribute { my $self = shift; if( @_ ) { $self->{attribute} = shift; } return $self->{attribute}; }
    1;


    TGI says moo