autobox::Closure::Attributes - closures are objects are closures


    use autobox::Closure::Attributes;
    use feature 'say';

    sub accgen {
        my $n = shift;
        return sub { ++$n }

    my $from_3 = accgen(3);

    say $from_3->n;     # 3
    say $from_3->();    # 4
    say $from_3->n;     # 4
    say $from_3->n(10); # 10
    say $from_3->();    # 11
    say $from_3->();    # 12
    say $from_3->m;     # "CODE(0xDEADBEEF) does not close over $m"


The venerable master Qc Na was walking with his student, Anton. Hoping to prompt the master into a discussion, Anton said "Master, I have heard that objects are a very good thing - is this true?" Qc Na looked pityingly at his student and replied, "Foolish pupil -- objects are merely a poor man's closures."

Chastised, Anton took his leave from his master and returned to his cell, intent on studying closures. He carefully read the entire "Lambda: The Ultimate..." series of papers and its cousins, and implemented a small Scheme interpreter with a closure-based object system. He learned much, and looked forward to informing his master of his progress.

On his next walk with Qc Na, Anton attempted to impress his master by saying "Master, I have diligently studied the matter, and now understand that objects are truly a poor man's closures." Qc Na responded by hitting Anton with his stick, saying "When will you learn? Closures are a poor man's objects." At that moment, Anton became enlightened.


This module uses powerful tools to give your closures accessors for each of the closed-over variables. You can get and set them.

You can get and set arrays and hashes too, though it's a little more annoying:

    my $code = do {
        my ($scalar, @array, %hash);
        sub { return ($scalar, @array, %hash) }

    $code->scalar # works as normal

    my $array_method = '@array';
    $code->$array_method(1, 2, 3); # set @array to (1, 2, 3)
    $code->$array_method; # [1, 2, 3]

    my $hash_method = '%hash';
    $code->$hash_method(foo => 1, bar => 2); # set %hash to (foo => 1, bar => 2)
    $code->$hash_method; # { foo => 1, bar => 2 }

If you're feeling particularly obtuse, you could do these more concisely:

    $code->${\ '%hash' }(foo => 1, bar => 2);
    $code->${\ '@array' }

I recommend instead keeping your hashes and arrays in scalar variables if possible.

The effect of autobox is lexical, so you can localize the nastiness to a particular section of code -- these mysterious closu-jects will revert to their inert state after autobox's scope ends.


Go ahead and read the source code of this, it's not very long.

autobox lets you call methods on coderefs (or any other scalar).

PadWalker will let you see and change the closed-over variables of a coderef .

AUTOLOAD is really just an accessor. It's just harder to manipulate the "attributes" of a closure-based object than it is for hash-based objects.


    <#moose:jrockway> that reminds me of another thing that might be insteresting:
    <#moose:jrockway> sub foo { my $hello = 123; sub { $hello = $_[0] } }; my $closure = foo(); $closure->hello # 123
    <#moose:jrockway> basically adding accessors to closures
    <#moose:jrockway> very "closures are just classes" or "classes are just closures"


Shawn M Moore,


autobox, PadWalker

The "DESCRIPTION" section is from Anton van Straaten:


    my $code = do {
        my ($x, $y);
        sub { $y }
    $code->y # ok
    $code->x # CODE(0xDEADBEEF) does not close over $x

This happens because Perl optimizes away the capturing of unused variables.


Copyright 2007-2016 Shawn M Moore.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.