Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

OOP By Any Other Name

by Anonymous Monk
on Feb 25, 2011 at 23:39 UTC ( [id://890230]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I was brainstorming OOP perl and came up with the following. Certainly it can't be new, so I'd like to know if it has name. Thanks!
#!/usr/bin/perl use warnings; use strict; sub new_counter { my ($start) = @_; my %internal = ( count => $start ); my %external; $external{add} = sub { my ($value) = @_; $internal{count} += $value; }; $external{get} = sub { return $internal{count}; }; return \%external; } my $ctr = new_counter(7); print "Start: " . $ctr->{get}() . "\n"; $ctr->{add}(3); print "End: " . $ctr->{get}() . "\n";

Replies are listed 'Best First'.
Re: OOP By Any Other Name
by GrandFather (Saint) on Feb 25, 2011 at 23:49 UTC

    Using a hash in that fashion is generally referred to as dispatching and the hash is a "dispatch table". Contrast the technique with more usual Perl OO:

    use strict; use warnings; package Counter; sub new { my ($class, $start) = @_; return bless {count => $start}, $class; } sub add { my ($self, $value) = @_; $self->{count} += $value; } sub get { my ($self) = @_; return $self->{count}; } package main; my $ctr = Counter->new (7); print "Start: " . $ctr->get () . "\n"; $ctr->add (3); print "End: " . $ctr->get () . "\n";
    True laziness is hard work
      But here one has encapsulation of data in %Internal... (a la Inside-out objects.) Downsides: @ISA isn't going to allow inheritance, not sure if closed methods take up more memory with each instance. Upside: I feel that it is syntactically cleaner than bless. But my feeling don't count for much.

        Ah, I wasn't sure just what aspect of the code you were most interested in. A more traditional approach to inside out objects goes something like this:

        use strict; use warnings; use Data::Dump; package Counter; my %data; sub new { my ($class, $start) = @_; my $lu; my $self = bless \$lu, $class; $data{$lu = "$self"} = {count => $start}; return $self; } sub add { my ($self, $value) = @_; $self = $data{$$self}; $self->{count} += $value; } sub get { my ($self) = @_; $self = $data{$$self}; return $self->{count}; } package main; my $ctr = Counter->new (7); print "Start: " . $ctr->get () . "\n"; $ctr->add (3); print "End: " . $ctr->get () . "\n";

        which gains the data hiding without losing Perl's normal OO support.

        The largest downside I see with the code you suggested is declaring all the anonymous subs in the constructor - that just doesn't scale well to anything other than toy code and is syntactically much nastier in my view.

        True laziness is hard work
        ... not sure if closed methods take up more memory with each instance...

        They have to bind to the correct (and often unique) lexical environment, but that's about it.

        not sure if closed methods take up more memory with each instance

        There will be some table of pointers (a pad) so for captured and local lexicals. The opcode tree itself won't be duplicated.

Re: OOP By Any Other Name
by roboticus (Chancellor) on Feb 25, 2011 at 23:50 UTC

    I believe it's called a closure. You've created a pair of functions which capture the counter variable. Then you can use those functions to modify the enclosed variable.

    Update: Repaired the link.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

Re: OOP By Any Other Name
by ikegami (Patriarch) on Feb 26, 2011 at 07:28 UTC

    You are using two techniques. I don't know which you are asking about.

    • You are using closures to privatise attributes. (Contrary to what others have said, you don't have "a closure". Each of your methods are closures.) I don't know if using closures for this purpose has a name.

    • You have per-object methods instead of classes. JavaScript uses this. It's called Prototype-based programming. Except you don't actually support prototypes.

    By the way, why create %internal at all?

    sub new_counter { my ($start) = @_; my $count = $start; return { add => sub { my ($value) = @_; $count += $value; }, get => sub { return $count; }, }; }
    Or even
    sub new_counter { my ($count) = @_; ... }
Re: OOP By Any Other Name
by sapphirecat (Acolyte) on Feb 26, 2011 at 02:17 UTC

    As mentioned, what you have is a closure. When someone introduced me to Lisp and closures a few years back, I began to suspect closures and OOP as I knew it were equivalent, so I hacked up my own "OOP system" using Perl's functional programming constructs, and just for lulz, a "closure object" in PHP. They're the first thing on this page, if you're interested in seeing my results.

    You may also be interested in this response to one of Paul Graham's articles; the response talks about what people think OOP means.

    (Some edits made for clarity.)

    "Basically, displaying invisible data is not maintainable."
Re: OOP By Any Other Name
by ikegami (Patriarch) on Feb 26, 2011 at 07:47 UTC

    Be careful. If any of the anon subs capture %external or a variable that references %external (directly or indirectly), you'll have a memory leak. The destructor should empty %external to kill any reference loops.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://890230]
Approved by GrandFather
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (6)
As of 2024-04-19 04:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found