Scott Walters > autobox-Closure-Attributes-0.05_1 > autobox::Closure::Attributes



Annotate this POD


Open  0
View/Report Bugs
Module Version: 0.05_1   Source  


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


Version 0.03 released 16 May 08


    use autobox::Closure::Attributes;

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

    my $from_3 = accgen(3);

    $from_3->n     # 3
    $from_3->()    # 4
    $from_3->n     # 4
    $from_3->n(10) # 10
    $from_3->()    # 11
    $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 also call invoke methods defined in the package the coderef was created in:

        package Foo;
        sub new {
            my $package = shift;
            my $x = shift;
            sub {
                $x *= 2;
        sub inc_x { my $self = shift; ++ $self->x }
    my $foo = Foo->new(10);
    $foo->inc_x;     # $x is now 11; calls the method inc_x
    $foo->x = 15;    #           15; assigns to $x
    $foo->x(20);     #           20; assigns to $x
    $foo->();        #           40; runs the sub { }
    $foo->m;         # "CODE(0xDEADBEEF) does not close over $m"

Note that the coderef returned by sub { } was never blessed.

If Foo is used from a different file with use, then you'll need this boilerplate in your

        sub import {
            my $class = shift;
            $class->autobox::import(CODE => 'autobox::Closure::Attributes::Methods');

That enables autoboxing of code references in the program that uses the module.

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 "WHAT?" 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.

Perl 5.8.9, 5.10.0, 5.12.0, and other earlier versions fail on the package method examples with the error: Can't modify non-lvalue subroutine call at /home/knoppix/lib/perl5/site_perl/5.8.9/autobox/Closure/ line 37. Change the mutators to instead read:

    sub inc_x :lvalue { ++ $_[0]->x; $_[0]->x }
    sub inc_y :lvalue { ++ $_[0]->y; $_[0]->y }

5.14 onward are smart enough to know that those accessors aren't actually called in lvalue context even though they're called from an lvalue method (AUTOLOAD).


Copyright 2007-2009 Shawn M Moore.

Copyright 2013 Scott Walters (scrottie).

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

syntax highlighting: