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