Anonymous subroutine objects pattern
In computer programming, Anonymous subroutine objects pattern is one of design patterns.
Problem
Perl's Object-oriented programming interface sucks. Instance variables
are slow to access, and require a special syntax that is unsightly and
prevents easily converting procedural code to OO code. Subclass data
can clobber superclass instance data unless manually prefixed with
the class name. Or, you just want to integrate the LambdaProgramming
style with the Object-oriented programming style to harness their
respective strengths.
Solution
Mix Object-oriented and Lambda programming[?] styles to deal with the ugliness
of Perl's InstanceVariables syntax, write more concise program, and use
scopes for implicit data flow rather than manually passing to and reading
from constructors.
Lambda programming's concept of automatically binding code to a
perticular variable created at a perticular time is the perfect replacement
for using hashes or arrays to contain instance data. Instead, routines
magically hang on to the normal scalars, hashes, arrays, and so forth
that were defined with //my// when the object was created. All that is
needed is a block to set up the lexical context (define the //my// variables
in) and a little glue.
Blessed Coderef
One of the strengths of the LambdaProgramming style is ease of
doing things like InnerClasses. Logic and data can be bundled without
having to type out the name of each variable to pass it to a constructor,
and without having to read it and assign it names in the constructor.
Instead, the new object is automagically coupled to the object that
it was created in, and variables that are in scope when the new object
was created remain in scope and available for use in future calls.
You should be familiar with this by now:
The string "color" appears ten times. Ten! In Perl, no less. If I wrote out the
constructors for the other arguments, this would be repeated for each variable.
Shame. If we trust the user to pass in the right things to the constructor, we
can get rid of two. Still, even typing each thing eight times is begging for a
typo to come rain on your parade.
If you're a LISP or Scheme programmer, you wouldn't even consider writing an
autocracy like this. You'd probably write something like:
First, the //{ query_name => sub { } }->{$arg}->(@_)// is a sort of switch/case
statement. It creates an anonymous hash of names to functions, then looks up
one of the functions by name, using the first argument passed in. Once we have
that code reference, we execute it and pass it our unused arguments. Then we've
added a default case to it, so we don't try to execute undef as code. This could
have been coded using if/elsif/else just as easily.
Don't confuse the this case idiom //{name=>sub{}}->{$arg}->(@_)// with //=8>-()<//, the
rubber chicken idiom.
The //get_preferences()// routine sets some variables, then returns a code reference.
//my// variables get created when they're declared, and they don't get destroyed
until no one can see them any more. Since the code reference we're returning
when we say //return MessageMethod sub { }// can see these variables, and we can
see this code reference, Perl doesn't get rid of them. They continue to live on,
and keep their same values, as if the subroutine they were created in had never
returned. What this means to us is that we don't have to copy the value from
one variable into a hash when we create an object! This saves us having type
the variable name as we pass it, specify what the variable should be named in
the hash that gets passed, then goes on to save us from having to do the same
steps in reverse once the object gets the hash passed to it. With the same
security, we've cut the use of the word "color" in half, down to 5 uses.
If you think of Perl's sub { } feature as preserving the exact state of "my"
variables in a routine, you'll think of countless applications for returning
anonymous subroutines. Object Oriented object creation is much more explicit,
so you may find yourself getting lost in code like this. If you figure out
where an anonymous subroutine was defined, then start reading the code leading
up to it, you'll find where the variables are declared, and where their values
are set. The cost of the reduced typing is reduced redundancy, which can make
the program both harder and easier to read at the same time.
Normal Objects:
Lexically Defined Object:
There is one little mystery left, though. Code references are dereferenced
using the //$ref->(@args)// syntax. //$ref->function(@args)// syntax is
reserved for objects. We shouldn't be able to call $ob->get_street() in our
example on a code reference -- unless that code reference has been blessed into
a package. It just so happens that that is exactly what //MessageMethod// does.
Given a code reference, //MessageMethod// blesses it into its own package. There
are no methods aside from //new()// and //AUTOLOAD()//. //AUTOLOAD()// handles undefined methods
for Perl, and since there are no methods, it handles all of them. (There is an
exception to that, where new() has to pass off requests). //AUTOLOAD()// merely
takes the name of the function it is standing in for and sends that as the first
argument to a call to the code reference, along with the rest of the arguments.
We're translating //$ob->foo('bar')// into //$ob->('foo', 'bar')//. This does nothing
but let us decorate our code reference with a nice OO style syntax.
This is similar to Python's method lookup logic XXX, in that it returns the method as an object.
Blessed Hash full of Coderefs
The previous example was simplicity itself. This one is usefullness itself.
Doing //if// and //elsif// in a chain to inspect an argument to see which
clause to run to simulate methods is the LambdaProgramming paradigm, but
ObjectOriented's concept of automatically dispatching to methods is
superior. Obviously, a single code reference isn't enough to let OO
do its dispatch magic. We need something larger - something like a hashref
that contains a bunch of coderefs, one coderef per method. The normal
thing to do in Perl is to put all of the code directly in the package,
using the symbol table (or stash, or namespace, or what have you) to
hold all of the code references, and define the code references using a
simple named //sub// statement. This doesn't allow each instance of
the object to have different code references lexically bound to different
InstanceVariables. We need private storage for the code references
and the anonymous version of the //sub// statement. We need //hashclosure.pm//.
This code translates method calls into invocations of anonymous subroutines
by the same name inside of a blessed hash: when a method is called, we look
for a hash element of that name, and if we find it, we execute it as a code
reference.
XXX - diagram here.
Dropping the above code verbatum into a .pm file it doesn't change package
(there is no //package// statement),
so it defines an //AUTOLOAD()// method for the current package.
This is a WrapperModule of sorts. LambdaClosures and our //AUTOLOAD()//
method work together to provide ImplicitThis-like easy access to //$this//
and InstanceVariables. We can use object instance specific field
variables directly without having to dereference a hash.
This blesses an anonymous hash reference into our package, //Foo//. This
hash reference contains method names as keys and anonymous subroutines as
values. //AUTOLOAD()// knows how to look into our hash and find methods
by name, and run them, rather than looking for methods in the normal place.
//our// is a strange beast. It gives us a //my// style lexical alias to a //local//
style variable. We could use a //local// variable here, but //our// has a nicer
syntax, and it keeps us in the lexical mode of thought.
//$foo//, //$bar//, //$this//, //$class// and //%args// are all lexical variables,
and the subroutines we create with //sub { }// are LambdaClosures because they
reference these variables. By referencing them, they bind to the one specific copy
that was created when //new()// is entered. That means that each object has its
own private //$foo//, for instance, and can access it directly. //get_qux()// is defined
as a normal method in the preceding example. In any OO Perl code, failing to do
something like //$this->method()// to call other functions in your code prevents
inheritance from overriding those methods. Using this syntax keeps open the
possibility of creating TemplateMethod. Where we explicit don't want subclass
redefinitions of methods to be used, way can use the //$this->Foo::method()// syntax,
where //Foo// is the name of the class to search for //method()// in, usually our
own package or our direct parent.
Methods may also be defined normally and placed next to //new()//. This is
useful for utility methods, or //static// methods in C++ or Java. Methods
must be defined this way to be called without using the //$this->method()// syntax.
//$this->method()// is required to get the //AUTOLOAD()// logic to kick in as
otherwise Perl has no knowledge of how to locate the code responsible for handing
your method.
This is my own personal favorite idiom for creating objects in Perl: it requires
the least code to acheive, and the least work on my part, and the least chance
of error.
In other news, PerlMonks:116725 defines a //class// package usabe as such:
...allowing the anonymous, inline construction of classes.
package Preferences;
sub new {
my $class = shift;
my %args = @_;
bless {color=>$args{'color'}, petname=>$args{'petname'}, street=>{'street'} }, $class;
}
sub query_color { return $_[0]->{'color'}; }
sub set_color { return $_[0]->{'color'} = $_[1]; }
# other accessors here
1;
package main;
$| = 1;
print "Whats your favorite color? "; my $color = <STDIN>;
print "Whats your pets name? "; my $petname = <STDIN>;
print "What street did you grow up on? "; my $street = <STDIN>;
my $foo = new Preferences (color=>$color, petname=>$petname, street=>$street);
package main;
$| = 1;
sub get_preferences {
print "Whats your favorite color? "; my $color = <STDIN>;
print "Whats your pets name? "; my $petname = <STDIN>;
print "What street did you grow up on? "; my $street = <STDIN>;
return MessageMethod sub {
my $arg = shift;
({
query_color => sub { return $color; }
set_color => sub { $color = shift; return 1; }
# etc
}->{$arg} || sub { die "Unknown request: $arg" })->(@_);
};
}
my $ob = get_preferences();
print $ob->get_street(), "\n";
the block they were defined in.
package MessageMethod;
sub new {
my $type = shift;
return $type->new(@_) if ref $type eq __PACKAGE__;
my $ref = shift; ref $ref eq 'CODE' or die;
bless $ref, $type;
}
sub AUTOLOAD {
my $me = shift;
(my $method) = $AUTOLOAD =~ m/::(.*)$/;
return undef if $method eq 'DESTROY';
return wantarray ? ($me->($method, @_)) : scalar $me->($method, @_);
}
1;
# place this code in hashclosure.pm
# tell Perl how to find methods in this object - run the lambda closures the object contains
sub AUTOLOAD {
(my $method) = $AUTOLOAD =~ m/::(.*)$/;
return if $method eq 'DESTROY';
our $this = shift;
if(! exists $this->{$method}) {
my $super = "SUPER::$method";
return $this->$super(@_);
}
$this->{$method}->(@_);
}
1;
package Foo;
sub new {
my $class = shift;
my %args = @_;
our $this;
my $foo;
my $bar;
bless {
get_foo => sub { return $foo },
set_foo => sub { $foo = shift },
get_bar => sub { return $bar },
set_bar => sub { $bar = shift },
get_foo_bar_qux => sub {
return $this->get_foo(), $this->get_bar(), get_qux();
},
dump_args => sub {
foreach my $i (keys %args) {
print $i, '=', $args{$i}, "\n";
}
},
}, $class;
}
sub get_qux { return 300; }
my $class = new class sub{
my $field = shift;
$this->field = $field;
$this->arrayref = [1,2,3];
$this->hashref = {a => b, c => d};
$this->method = sub{ return $this->field };
};
See also: