Closures



A subroutine that generates subroutines based on some input values.


examples/references/incrementer.pl
#!/usr/bin/perl
use strict;
use warnings;

sub incrementer {
    my $old = $_[0];
    $_[0] += $_[1];
    return $old;
}

my $x = 23;
my $old = incrementer($x, 19);
print "$old  $x\n"; # 23  42

sub incrementer_23 {
    my $inc = 23;
    my $old = $_[0];
    $_[0] += $inc;
    return $old;
}

examples/references/incrementer-generator.pl
#!/usr/bin/perl
use strict;
use warnings;

sub incrementer_generator {
    my ($inc) = @_;

    return sub {
        my $old = $_[0];
        $_[0] += $inc;
        return $old;
    }
}

my $inc19 = incrementer_generator(19);

my $x = 23;
my $old_value = $inc19->($x);
print "$x\n";
print "old after inc19: $old_value\n";


my $inc5 = incrementer_generator(5);
print "old after inc5: " . $inc5->($x) . "\n";
print "$x\n";

my $prev_value = $inc19->($x);
print "old after inc19: $prev_value\n";
print "$x\n";

Output:


42
old after inc19: 23
old after inc5: 42
47
old after inc19: 47
66


examples/functional/Transformers.pm
package Transformers;
use strict;
use warnings;
use Time::HiRes qw(time);

use Exporter qw(import);
our @EXPORT_OK = qw(show_elapsed_time);

sub show_elapsed_time {
    my (@subs) = @_;
    my $caller = caller();
    for my $sub (@subs) {
        my $name = "${caller}::$sub"; # fully qualified name

        no strict 'refs';
        my $subref = \&$name;
        my $new = sub {
            my $start = time;
            my (@results, $result);
            if (wantarray) {
                @results = $subref->(@_);
            } elsif (defined wantarray) {
                $result = $subref->(@_);
            } else {
                $subref->(@_);
            }
            my $end = time;
            my $elapsed = $end - $start;
            print "Elapsed time of $name: $elapsed\n";
            return wantarray ? @results : $result;
        };

        no warnings 'redefine';
        *{$name} = $new;
    }
    return;
}


1;

examples/functional/add_logging.pl
use strict;
use warnings;

sub count {
    my ($limit) = @_;
    print "count till $limit\n";
    my $counter = 0;
    $counter++ while $counter < $limit;
}

sub show_elapsed {
    my ($sub) = @_;

    use Time::HiRes qw(time);
    return sub {
        my $start = time;
        $sub->(@_);
        my $end = time;
        my $elapsed = $end - $start;
        print "Elapsed time: $elapsed\n";
    }
}

my $newcount = show_elapsed(\&count);
$newcount->(10000000);
#*count = $newcount;

count(10000000);

examples/functional/add_logging_replace.pl
use strict;
use warnings;
use lib '.';
use Transformers qw(show_elapsed_time);

show_elapsed_time('count', 'add', 'calc');

sub count {
    my ($limit) = @_;
    print "count till $limit\n";
    my $counter = 0;
    $counter++ while $counter < $limit;
}

sub add {
    my ($x, $y) = @_;
    print "Add $x + $y\n";
    return $x+$y;
}

sub calc {
    my ($x, $y) = @_;
    print "Calc $x $y\n";
    return $x+$y, $x*$y;
}



count(10000000);
my $res = add(2, 3);
print "Res: $res\n";

my @res = calc(2, 3);
print "Res: @res\n";