Hi!

On Tue, Dec 1, 2009 at 10:56 PM, Ludwig Isaac Lim <[email protected]> wrote:
> Hi:
>
>   I'm having some hard time understand perl closure:
>
>   Here's an explanation from Intermediate Perl:
>   "The kind of subroutine that can access lexical variables that existed at 
> the time we declare it is called a closure .....In Perl terms, a closure is 
> just a subroutine that references a lexical variable that has gone out of 
> scope".
>
>   and here is the sample code:
>   use File::Find;
>
>   my $total_size = 0;
>   find (sub {$total_size += -s if -f},'.');
>   print $total_size, "\n";
>
>
>    My question is "$total_size" is not out of scope since it is declared 
> before "find(sub.." right?

Not out of scope in where find() is, but it is out of scope in
find()'s code where the coderef gets evaluated.

>   Can we say closures are anonymous coderefs that acesses a pre declared 
> variable?

Usually, but not always.

Closures in Perl are best illustrated using BLOCKs, e.g.

{
    my $scalar = "Just Another Perl Hacker";

    sub get_scalar { return $scalar }
}

{
    my $scalar = "Yet Another Perl Hacker";

    use feature ':5.10'
    say $scalar;        # "Yet Another Perl Hacker"
    say get_scalar;     # "Just Another Perl Hacker"
}

Notice the above two blocks.  Both blocks contain a definition of the
the lexical $scalar, but the first block contains a named subroutine
that gets its own "closed" $scalar.  The first block's $scalar is
inaccessible by any code outside of the block, except through the
subroutine.  So, as the latter block contains its own $scalar
variable, it can still get the value of the other $scalar through the
subroutine closure.

Another example of closures relates to their use as encapsulations for
an object's implementation.  Consider a simple Point object: here's a
classic implementation:

package Point::Simple;

sub new {
    my ( $class, $x, $y ) = shift;
    my $self = {
        x => $x,
        y => $y,
    };
    return bless $self => $class;
}

sub x { return $_[0]->{x} }
sub y { return $_[0]->{y} }

1;

And here's a closure-based implementation:

package Point::Closure;

sub new {
    my ( $class, $x, $y ) = @_;
    my $self = {
        x => undef,
        y => undef,
    };
    my $c = sub {
        my $field = shift;
        if (@_) { $self->{$field} = shift }
        return    $self->{$field};
    };
    return bless $c => $class;
}

sub x { $self->("x", @_[ 1 .. $#_ ] ) }
sub y { $self->{"y", @_[ 1 .. $#_ ] ) }

1;


Granted, the Point::Closure implementation looks more complex, but on
the plus side, it adds a place where one can do some parameter
validation or preprocessing before anything else.  Say, one could
sprinkle some Carp::cluck calls in new() to add some boundary checks.

(As an aside, object-oriented programming in Perl is now a lot
simpler, thanks to Moose and friends.)

-- 
Zak B. Elep  ||  zakame.net
1486 7957 454D E529 E4F1  F75E 5787 B1FD FA53 851D
_________________________________________________
Philippine Linux Users' Group (PLUG) Mailing List
http://lists.linux.org.ph/mailman/listinfo/plug
Searchable Archives: http://archives.free.net.ph

Reply via email to