subroutines advanced

How to create a closure in Perl?

Question

How to create a closure in Perl?

In Perl, a closure is a subroutine that captures variables from its enclosing lexical scope, allowing it to access and retain those variables even after the outer subroutine has finished executing. Closures are powerful for creating private state, callbacks, and deferred computations.

Understanding Closures in Perl

Perl’s closures work because of my variables (lexical variables) and how Perl’s subroutines keep a reference to their surrounding lexical environment if they “close over” it. When a subroutine is returned or stored in a variable, it still has access to those lexicals, retaining their current state.

This differs from global variables (like $GLOBALS or our variables) because those are not “captured.” Only lexical variables declared with my are closed over by anonymous subs.

Key Concepts

  • my variables define lexical scope, crucial for closures.
  • A closure keeps references to lexicals even if the outer subroutine returns.
  • Closures are typically created as anonymous subs (using sub { ... }).
  • Different closures created inside the same subroutine maintain independent lexical environments.

Example: Creating and Using a Closure

This example defines a counter generator subroutine that returns a closure. Each closure maintains its own private count state.

#!/usr/bin/perl
use strict;
use warnings;

sub make_counter {
    my $count = 0;            # Lexical variable captured by closure
    return sub {
        $count++;             # Modify lexical variable
        return $count;
    };
}

# Create two independent counters
my $counter1 = make_counter();
my $counter2 = make_counter();

print "Counter 1: ", $counter1->(), "\n";  # 1
print "Counter 1: ", $counter1->(), "\n";  # 2
print "Counter 2: ", $counter2->(), "\n";  # 1 (separate state)
print "Counter 1: ", $counter1->(), "\n";  # 3
print "Counter 2: ", $counter2->(), "\n";  # 2

Each call to make_counter creates a new lexical $count. The anonymous sub returned retains access to this $count variable and modifies it. Even though make_counter has finished running, its lexical variable survives within the closure.

Common Pitfalls and Gotchas

  • Globals vs Lexicals: Using global variables (our or package variables) won't create true closures because they’re not lexically scoped.
  • Reference copying: Returning references to lexicals creates closures, but copying a subroutine with *foo = \&bar; does not make closures.
  • Beware of loop variables: Capturing loop variables can cause unexpected behavior if the variable changes. Use my inside the loop to create a new lexical for each iteration.
  • Perl versions: Basic closures have worked the same way since early Perl 5 versions. No special version requirements.

Summary

To create a closure in Perl:

  1. Define my lexical variables in an outer scope.
  2. Create and return an anonymous subroutine that refers to these lexicals.
  3. Call the returned subroutine. It retains access to the captured variables.

This programming pattern is elegant and powerful, enabling encapsulation and functional programming styles in Perl.

Verified Code

Executed in a sandbox to capture real output. • v5.34.1 • 7ms

Tip: edit code and use “Run (Browser)”. Server runs always execute the published, verified snippet.
STDOUT
Counter 1: 1
Counter 1: 2
Counter 2: 1
Counter 1: 3
Counter 2: 2
STDERR
(empty)

Was this helpful?

Related Questions