Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid

List Wrapper for Object Methods.

by pelagic (Curate)
on Dec 03, 2004 at 08:47 UTC ( #412067=perlquestion: print w/ replies, xml ) Need Help??
pelagic has asked for the wisdom of the Perl Monks concerning the following question:

Good morning monks!
I just ran into a "problem" with OO coding and I'm sure there's some elegant solution out there. So let's give it a try:

I got a Module Anything with a couple of methods. Now I want to have lists of Anything objects as Anything::List objects and I want to call the Anything methods on all objects in a Anything::List in a row.
That's easy of course but there are a lot of methods in Anything and all their Anything::List equivalents look exactly the same and thats actually bothering me!
And here is a snippet for demonstration:
package Anything; sub new { my $class = shift; ## ... code here bless $self, $class; } sub prepare_create { ## .. do something } sub create { ## .. do something else } ## a.s.o. more methods here package Anything::List; sub new { my $class = shift; my @self = @_; bless \@self, $class; } sub add { my $self = shift; push @$self, @_; } sub list { my $self = shift; return @$self; } sub prepare_create { my $self = shift; foreach my $anything (@{$self}) { $anything->prepare_create(@_); } } sub create { my $self = shift; foreach my $anything (@{$self}) { $anything->create(@_); } }
Thanks for some inspiring hints!


Comment on List Wrapper for Object Methods.
Download Code
Re: List Wrapper for Object Methods.
by Arunbear (Parson) on Dec 03, 2004 at 10:06 UTC
    You can use AUTOLOAD to do that
    our $AUTOLOAD; sub AUTOLOAD { my $self = shift; my $method = $AUTOLOAD; $method =~ s/.*://; # strip out Package:: foreach my $anything (@{$self}) { die "method $method not supported" unless $anything->can($method); $anything->$method(@_); } }
    Though this does smell like it would benefit from the composite design pattern.
      Thanks a lot Arunbear this works nicely.
      There's just one thing left for me:
      I see that my AUTOLOAD method now also "catches" calls for DESTROY and I don't know exactly what's happening then. Isn't the AUTOLOAD method a litte too generic?

        To get around that you can add the line
        return if $AUTOLOAD =~ /::DESTROY$/;
        at the beginning of the AUTOLOAD sub, or define a do-nothing DESTROY method (assuming you really don't have any cleanup to do). Perl calls the DESTROY method when it does garbage collection, even if you haven't defined a DESTROY method.
Re: List Wrapper for Object Methods.
by diotalevi (Canon) on Dec 03, 2004 at 12:36 UTC
      I freely admit: I'm not that experienced with OO.
      But instead of asking us all to Abandon hope you might be willing and able to post a hint on how to do it better.
      In case you would like to do so I put the POD of that code in question here: ---
      The idea to create the Class Archive::List is actually just to be able of serialising method invocations.

      (update: on dio's suggestion I put the POD directly into this node ....)

Re: List Wrapper for Object Methods.
by Prior Nacre V (Hermit) on Dec 03, 2004 at 13:38 UTC

    While I understand that this can be a little disconcerting, you shouldn't let it worry you.

    Tutorials typically indicate this with examples like:

    $game->draw; $sword->draw; $picture->draw; $blank->draw;

    As an analogy, consider navigating a directory structure. When you type cd lib you will either change to a new directory (dependent on the current directory) or receive an error message (if no lib directory exists). Similarly, invoking the method draw() will either run some code (dependent on the class of the invocant) or will produce an error (Can't find method ...).

    As you haven't indicated any inheritance in your question or code, I have avoided a discussion of polymorphism.

    A musing: Could the analogy be extended to include polymorphism if I used David Korn's version of cd?



Re: List Wrapper for Object Methods.
by dragonchild (Archbishop) on Dec 03, 2004 at 14:22 UTC
    Another option to Arunbear's use of AUTOLOAD (which is the standard Perl solution to delegation) is to build the methods programmatically.
    package Anything::List; use strict; # Include all the methods in this list that you # want to delegate to the Anything class my @delegate_methods = qw( prepare_create create ); foreach my $method (@delegate_methods) { # We're playing with the symbol table, here! no strict 'refs'; *$method = sub { my $self = shift; $_->$method( @_ ) for @$self; }; } # Continue on with the rest of the Anything::List class here.

    Being right, does not endow the right to be rude; politeness costs nothing.
    Being unknowing, is not the same as being stupid.
    Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
    Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

Re: List Wrapper for Object Methods.
by tall_man (Parson) on Dec 03, 2004 at 16:02 UTC
    There is a simpler way, using the trick found in Re: Dynamically constructed function calls. It looks a bit horrifying, but it's legal to pass a method name in a scalar variable.
    sub call_method_for_list { my $self = shift; my $method = shift; foreach my $anything (@{$self}) { $anything->$method(@_); } }

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://412067]
Approved by BrowserUk
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (5)
As of 2014-09-17 07:49 GMT
Find Nodes?
    Voting Booth?

    How do you remember the number of days in each month?

    Results (65 votes), past polls