Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation

Fun with Closures

by Schemer (Scribe)
on Mar 25, 2003 at 02:13 UTC ( [id://245595] : perlmeditation . print w/replies, xml ) Need Help??

While thinking about programming languages in a half-sleep the other day I found myself wondering about closures and objects.

I have a somewhat favorite language (reflected by my nickname) which allows easy generation and manipulation of closures. Often I have heard things about objects and closures being related.

Since my Perl knowledge is somewhat limited (I own the Camel book, but never read it in full), I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.

First I will pre-emptively apologize for the somewhat confusing "object" term I use, and admit I don't know much about Perl's real object system.

Ok, so I ended up with the following thing, which is basically a simple object system (message passing):

# an object is simply a closure with a hash of closures sub make_object { my %msg; $msg{"add-msg"} = sub { my $m = shift(); $msg{$m} = shift(); }; return sub { my $m = shift(); return $msg{$m} ? $msg{$m}->(@_) : print "unknown message\n"; } }
Basically, this creates an object that only has one "method" initially, which allows for the addition of other methods or slots ("member values"). Methods added are internally stored in a hash which is local to the object's closure.

Here is some example code using this thing:

# build an object my $object = make_object(); # add functions to our object &$object("add-msg", "status", sub {print "up and running\n"}); &$object("add-msg", "square", sub {return shift()**2}); # test the functions &$object("status"); # ==> displays "up and running" print &$object("square", 25.80697580112788) . "\n"; # ==> "666" # here is something fun... &$object("add-msg", "build-object", \&make_object); # ...objects can generate objects my $other_object = &$object("build-object"); &$other_object("status"); # ==> error, this is a distinct object &$other_object("add-msg", "status", sub {print "new object up\n"}); &$other_object("status"); # ==> display "new object up" # an object could manipulate itself &$object("add-msg", "get-self", sub {return $object}); &$object("get-self")->("add-msg", "test", sub {print "test ok!\n"}); &$object("test"); # ==> display "test ok!"

So what's the value of all of this? Well, I don't think this code could be of some use in practice, since it is more like a toy example and the syntax just doesn't cut it. But at the very least I had some fun writing it, and hopefully it can be seen as a demonstration of what closures allows you to do.

Comments, thoughts and/or insults would be appreciated! :-)


Replies are listed 'Best First'.
Re: Fun with Closures
by Anonymous Monk on Mar 25, 2003 at 02:24 UTC

    This is the same sort of thing you'll get if you start in with Class::Classless which is great fun. Along these lines curious perl programmers are encouraged to read E in a Walnut. The E language takes this idea further into the P2P space with faceted objects (but really you'd want to read the Walnut doc. Its short and mind-blowing if you aren't used to that sort of thing).

    BTW, this is diotalevi but since I just front-paged the post I figured I'd prevent your votes from getting back to me.

      The concepts of E are indeed interesting even though most of E seems to remain a pipe dream, as the last development I could find was v0.8 of 2000.

      Another classless implementation is Test::MockObject, it also implements "dynamic classes" (in Smalltalk style) to which you can add/remove methods dynamically.

      If one is interested in Promises (the one interesting feature of E), Object::Realize::Later implements this lazy loading of objects for Perl. Promises are a really nice way to implement concurrency within a program without having to think about locking or concurrent access : If you have a possibly long running action whose (independent) results are needed later on in your program, or maybe not at all, instead of running that action in your main thread, you spawn off a second thread that produces that result in the background and immediately returns a promise to the result. As soon as you access any method/field of the (promised) result, your main thread blocks until the background thread has produced the result. This allows you to easily enable/disable concurrency by changing one line within your code, at the cost of suboptimal efficiency - partial results (such as the first 20 rows of a database) require much more work.

      perl -MHTTP::Daemon -MHTTP::Response -MLWP::Simple -e ' ; # The $d = new HTTP::Daemon and fork and getprint $d->url and exit;#spider ($c = $d->accept())->get_request(); $c->send_response( new #in the HTTP::Response(200,$_,$_,qq(Just another Perl hacker\n))); ' # web
Re: Fun with Closures
by rjray (Chaplain) on Mar 25, 2003 at 02:27 UTC

    You seem to be on a good track with regards to understanding Perl's implementation of closures. I would further recommend reading of the perlref and perlobj manual pages. You may also find perlboot and perltoot helpful, as well.


Re: Fun with Closures
by jdporter (Chancellor) on Mar 25, 2003 at 02:28 UTC
    Sometimes called "inside-out objects". This node has pointers to other, related discussions as well.

    The 6th Rule of Perl Club is -- There is no Rule #6.

      Eh, no, using closures to create objects has nothing to do with Inside-Out Objects. Last year on YAPC::NA, I did give a talk discussing both Inside-Out Objects and an OO system based on closures, but there was nothing in common between the two.

      As for a closure based object system, including inheritance and AUTOLOAD, see OO::Closures on CPAN.


        You are quite right. I was thinking of your OO::Closures, and when I searched, came across your inside-out objects, and rashly conflated the two. Both are cool, but entirely distinct.

        The 6th Rule of Perl Club is -- There is no Rule #6.

Re: Fun with Closures
by dada (Chaplain) on Mar 26, 2003 at 08:11 UTC
    Schemer wrote:
    # an object could manipulate itself &$object("add-msg", "get-self", sub {return $object});

    I have to disagree with this one. you're not referring to "self" (in OO terms), but merely to the (lexical, in this case) variable $object. consider this:

    my $object = make_object(); &$object("add-msg", "get-self", sub {return $object}); my $copy = $object; print &$copy("get-self"), "\n"; $object = 42; print &$copy("get-self"), "\n";
    the output of this snippet is:
    CODE(0x18350d8) 42
    which shows that $copy is still an "object", but the second call to get-self returns the current value of $object (which is not an "object" anymore).


    King of Laziness, Wizard of Impatience, Lord of Hubris

Re: Fun with Closures
by hardburn (Abbot) on Mar 25, 2003 at 14:57 UTC

    Thanks. You have now been sig'd.

    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    Note: All code is untested, unless otherwise stated