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

Download:
autobox-Closure-Attributes-0.05_1.tar.gz

Dependencies

Annotate this POD

CPAN RT

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

NAME ^

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

VERSION ^

Version 0.03 released 16 May 08

SYNOPSIS ^

    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"

WHAT? ^

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.

DESCRIPTION ^

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 Foo.pm:

        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 Foo.pm 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.

HOW DOES IT WORK? ^

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.

WHY WOULD YOU DO THIS? ^

    <#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"

AUTHOR ^

Shawn M Moore, sartak@gmail.com

SEE ALSO ^

autobox, PadWalker

The "WHAT?" section is from Anton van Straaten: http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html

BUGS ^

    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/Attributes.pm 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 AND LICENSE ^

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: