Anonymous subroutine objects pattern

In computer programming, the anonymous subroutine object pattern is one of the design patterns.

Contents

Problem

Perl5's Object-oriented programming interface has many problems. 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 Lambda programming style with the Object-oriented programming style to harness their respective strengths.

Solution

Mix Object-oriented and functional 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 particular variable created at a particular 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:

 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);

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:

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

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:

  • Copy data - new values are independent.
  • Passed via arguments to a method call to new().
  • Method is called and evaluated when the object is created.

Lexically Defined Object:

  • Share variables - changes to variables inside the object are reflected inside and vice versa.
  • Never expicitly passed - instead, the rules of lexical scope are obeyed - must be referenced inside

the block they were defined in.

  • Method is created and returned when the object is created. It is not yet evaluated.

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.

 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;

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 usefulness 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//.

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

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 verbatim 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.

 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; }

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 achieve, and the least work on my part, and the least chance of error.

In other news, PerlMonks:116725 defines a //class// package usable as such:

   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 };
   };

...allowing the anonymous, inline construction of classes.

See also

External links

A Perl Design Patterns wiki (http://www.perldesignpatterns.com)

Navigation

  • Art and Cultures
    • Art (https://academickids.com/encyclopedia/index.php/Art)
    • Architecture (https://academickids.com/encyclopedia/index.php/Architecture)
    • Cultures (https://www.academickids.com/encyclopedia/index.php/Cultures)
    • Music (https://www.academickids.com/encyclopedia/index.php/Music)
    • Musical Instruments (http://academickids.com/encyclopedia/index.php/List_of_musical_instruments)
  • Biographies (http://www.academickids.com/encyclopedia/index.php/Biographies)
  • Clipart (http://www.academickids.com/encyclopedia/index.php/Clipart)
  • Geography (http://www.academickids.com/encyclopedia/index.php/Geography)
    • Countries of the World (http://www.academickids.com/encyclopedia/index.php/Countries)
    • Maps (http://www.academickids.com/encyclopedia/index.php/Maps)
    • Flags (http://www.academickids.com/encyclopedia/index.php/Flags)
    • Continents (http://www.academickids.com/encyclopedia/index.php/Continents)
  • History (http://www.academickids.com/encyclopedia/index.php/History)
    • Ancient Civilizations (http://www.academickids.com/encyclopedia/index.php/Ancient_Civilizations)
    • Industrial Revolution (http://www.academickids.com/encyclopedia/index.php/Industrial_Revolution)
    • Middle Ages (http://www.academickids.com/encyclopedia/index.php/Middle_Ages)
    • Prehistory (http://www.academickids.com/encyclopedia/index.php/Prehistory)
    • Renaissance (http://www.academickids.com/encyclopedia/index.php/Renaissance)
    • Timelines (http://www.academickids.com/encyclopedia/index.php/Timelines)
    • United States (http://www.academickids.com/encyclopedia/index.php/United_States)
    • Wars (http://www.academickids.com/encyclopedia/index.php/Wars)
    • World History (http://www.academickids.com/encyclopedia/index.php/History_of_the_world)
  • Human Body (http://www.academickids.com/encyclopedia/index.php/Human_Body)
  • Mathematics (http://www.academickids.com/encyclopedia/index.php/Mathematics)
  • Reference (http://www.academickids.com/encyclopedia/index.php/Reference)
  • Science (http://www.academickids.com/encyclopedia/index.php/Science)
    • Animals (http://www.academickids.com/encyclopedia/index.php/Animals)
    • Aviation (http://www.academickids.com/encyclopedia/index.php/Aviation)
    • Dinosaurs (http://www.academickids.com/encyclopedia/index.php/Dinosaurs)
    • Earth (http://www.academickids.com/encyclopedia/index.php/Earth)
    • Inventions (http://www.academickids.com/encyclopedia/index.php/Inventions)
    • Physical Science (http://www.academickids.com/encyclopedia/index.php/Physical_Science)
    • Plants (http://www.academickids.com/encyclopedia/index.php/Plants)
    • Scientists (http://www.academickids.com/encyclopedia/index.php/Scientists)
  • Social Studies (http://www.academickids.com/encyclopedia/index.php/Social_Studies)
    • Anthropology (http://www.academickids.com/encyclopedia/index.php/Anthropology)
    • Economics (http://www.academickids.com/encyclopedia/index.php/Economics)
    • Government (http://www.academickids.com/encyclopedia/index.php/Government)
    • Religion (http://www.academickids.com/encyclopedia/index.php/Religion)
    • Holidays (http://www.academickids.com/encyclopedia/index.php/Holidays)
  • Space and Astronomy
    • Solar System (http://www.academickids.com/encyclopedia/index.php/Solar_System)
    • Planets (http://www.academickids.com/encyclopedia/index.php/Planets)
  • Sports (http://www.academickids.com/encyclopedia/index.php/Sports)
  • Timelines (http://www.academickids.com/encyclopedia/index.php/Timelines)
  • Weather (http://www.academickids.com/encyclopedia/index.php/Weather)
  • US States (http://www.academickids.com/encyclopedia/index.php/US_States)

Information

  • Home Page (http://academickids.com/encyclopedia/index.php)
  • Contact Us (http://www.academickids.com/encyclopedia/index.php/Contactus)

  • Clip Art (http://classroomclipart.com)
Toolbox
Personal tools