in reply to Closures and callbacks...

I'd like to point out that these aren't really closures... You're doing this one hundred percent, and there's nothing wrong. Closures, however, contain copies of lexical values that they were created beside, and those copies are kept independantly for each instance of the closure. For example:
sub add { my $var = shift; sub { $var + $_[0] }; } my $bar = add(3); my $foo = add(5); $\ = "\n"; print &$bar(6); print &$foo(6);
This can be useful for initiallizing once, something that must be done repeatedly - in principal similar to objects.

Update: See more accurate closure definition in broquaint's reply.

Update: I apologize for all the inacuracies, please consider my node deprecated... ;-)
I may have been having too much sugar and not enough sleep at the time...

-nuffin
zz zZ Z Z #!perl

Replies are listed 'Best First'.
Re: Re: Closures and callbacks...
by broquaint (Abbot) on Oct 23, 2002 at 11:46 UTC
    I'd like to point out that these aren't really closures...
    The read_row function is a closure, it just happens to be a non-encapsulated closure as process can also see @indexes. It would act as a more effective closure if it was re-structured like so
    use Symbol; { my @indexes = qw (3 0 4 5 6 7); my $fh = gensym; open $fh,"<my.dat" or die "my.dat: $!"; sub read_row { my $row = <$fh>; close $fh and return unless defined($row); return (split(/\s+/,$row))[@indexes]; } }

    HTH

    _________
    broquaint

      I'm still very new to closures, but I just don't get it. Why is read_row a closure? Doesn't read_row just return a list of values, instead of code?

      -- Dan

        Why is read_row a closure?
        Because it is saving lexical state by referring to a lexical variable that is above the immediate lexical state. So if you call main::read_row from another package that isn't in the same lexical scope as read_row, it will still work even though @indexes is no longer in scope. This is because the lexical variable @indexes was saved by read_row, ergo, it is a closure. I hope that makes as much sense as I think it does. Hopefully (time forbidding) I'll write up a closure tutorial so I can merlyn any future closure questions ;)
        Doesn't read_row just return a list of values, instead of code?
        Returning an anonymous sub does not define a function as a closure, see the above explanation for why read_row qualifies as a closure.
        HTH

        _________
        broquaint

Re: Re: Closures and callbacks...
by jdporter (Paladin) on Oct 23, 2002 at 16:09 UTC
    I'd like to point out that all the forms of read_row presented above are in fact closures. It is closed over the lexical variable @indexes.

    nothingmuch's explanation of closures is not correct. A closure does not contain a "copy" of the lexical variable, nor is the variable "kept independently for each instance". Quite the opposite: a closure maintains a reference to a lexical variable outside its scope, and all instances of the closure(s) all refer to the exact same variable that was in existence at the time the closure was created.

    For variables and functions which are instantiated at compile time, as in the original post, the situation is very simple. Here's two functions which are both closed over the same variable:

    my @indexes = qw (3 0 4 5 6 7); open INDATA,"< my.dat" or die "my.dat: $!"; sub read_row { my $row = <INDATA>; return unless defined($row); return (split(/\s+/,$row))[@indexes]; } sub get_indexes { return @indexes; }
    Closures get more useful, but more tricky, when the functions in question are generated at runtime. Here's how I would make the original poster's code more useful by creating the closure on the fly:
    use IO::File; sub process_each_file_line { my( $filename, $preprocess_cb, $process_cb ) = @_; my $fh = IO::File->new( "< $filename" ) or die "open $filename for reading: $!"; while ( <$fh> ) { $process_cb->( $preprocess_cb->() ); } } sub process { my( $filename, @indexes ) = @_; my @result; process_each_file_line( $filename, sub { (split)[ @indexes ] }, sub { local $" = ','; push @result, "test : @_\n"; } ); return @result; } # call the function: print process( "my.dat", qw( 3 0 4 5 6 7 ) );
    Within the process function, the first anonymous sub (sometimes referred to as a "lambda" -- don't ask) is closed over the @indexes variable, and the second one is closed over @result.

    Since @indexes and @result are scoped to the process function, new instances of them are created each time process is called. And the two closures that use them have the same lifetimes. What happens if the closures live longer than the variables they're closed over? Perl does the right thing: it keeps the lexical variables alive. It's all just reference-counting, after all. A (rather contrived) example follows.

    use IO::File; sub process_each_file_line { my( $filename, $preprocess_cb, $process_cb ) = @_; my $fh = IO::File->new( "< $filename" ) or die "open $filename for reading: $!"; while ( <$fh> ) { $process_cb->( $preprocess_cb->() ); } } sub make_file_processor { my( $filename, @indexes ) = @_; return sub { # make a closure which takes no args. my @result; process_each_file_line( $filename, sub { (split)[ @indexes ] }, sub { local $" = ','; push @result, "test : @_\n"; } ); return @result; } } # create the processor for the given input params: my $processor = make_file_processor( "my.dat", qw( 3 0 4 5 6 7 ) ); # later on, call the closure: print $processor->();
    In this example, we actually have two levels of closures. The third argument to process_each_file_line (the second lambda) is closed over @result, which exists one lexical level above. But the second argument (the first lambda) is closed over @indexes, which exists two lexical levels above. Not that it's any big deal; perl lets us do this, and takes care of all the nasty reference bookkeeping.

    Disclaimer: The above code was not tested before posting, and may contain bugs.