Re: Method Calls on multiple objects
by bart (Canon) on Mar 27, 2004 at 00:13 UTC
|
No, it seems to me that what the original did, was allow all methods these object can do, on them all. In fact it sound a lot like tee — which is what I'd base the name of this module on.
Anyway, you original approach looks good to me, except I'd cache the sub, so AUTOLOAD isn't repeatedly called for each method.
sub AUTOLOAD {
my $self = shift;
if (my($method) = $AUTOLOAD =~ /::([^:]+)$/ ) {
no strict 'refs';
*$AUTOLOAD = sub {
my $self = shift;
$_->$method(@_) for @$self;
};
$self->$AUTOLOAD(@_);
}
}
That appears to work, at first sight.
I'm not sure it's actually better/faster.
p.s. Your original calls don't look right, it should be
my $obj_multi = MulitiObject->new( $obj_1, $obj_2 );
$obj_multi->foo($x, $y); # $obj_1->foo($x, $y); $obj_2->foo(
+$x, $y);
Oh, and make to constructor
sub new {
my $class = shift;
return bless [ @_ ], $class;
}
I don't trust takling references to @_. | [reply] [d/l] [select] |
Re: Method Calls on multiple objects
by DamnDirtyApe (Curate) on Mar 27, 2004 at 01:58 UTC
|
Nice module, L~R, but I'm just not seeing how this is inherently better than using what Perl already gives you.
#! /usr/bin/perl
use strict;
package Dog;
sub new {
my $class = shift;
my $self = {};
return bless $self, $class;
}
sub bark { print "Woof!\n"; }
package main;
my $fido = Dog->new();
my $woofy = Dog->new();
$_->bark for ( $fido, $woofy );
Is this not just as effective? Or am I missing something?
_______________
DamnDirtyApe
Those who know that they are profound strive for clarity. Those who
would like to seem profound to the crowd strive for obscurity.
--Friedrich Nietzsche
| [reply] [d/l] |
|
|
DamnDirtyApe,
Or am I missing something?
Not really. You would have to modify it only slightly to allow argument passing. The big difference is that with:
$obj_merged->bark( 'mailman' );
You get the benefit of not having to remember how many/which objects (which could be of different classes) are in the merged object. It also becomes a heck of a lot easier depending on how many times you want to bark at the moon. This is why I do not think my second example would be desireable to the person asking either.
Keep in mind I am not suggesting a new module for CPAN by any stretch of the imagination - just something to help someone who asked.
Cheers - L~R | [reply] [d/l] |
Re: Method Calls on multiple objects
by dragonchild (Archbishop) on Mar 27, 2004 at 01:59 UTC
|
I'm a little confused ... What benefit does this provide? As far as I can tell, this is basically a rewriting (and complicating) of:
$_->$method(@args) for @objects;
Personally, I don't see a need for calling the same method on a number of objects. If you need an aggregate, create an aggregate. This, to me, would be a red flag in a code review.
------
We are the carpenters and bricklayers of the Information Age.
Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose
| [reply] [d/l] |
|
|
my @rets = map { $_->$method( @args ) } @objs;
Or allowing returns of lists:
my @rets = map { [ $_->$method( @args ) ] } @objs;
| [reply] [d/l] [select] |
|
|
So, why would an aggregate be better? What syntactic sugar are you looking for?
------
We are the carpenters and bricklayers of the Information Age.
Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose
| [reply] |
|
|
|
|
Personally, I don't see a need for calling the same method on a number of objects. If you need an aggregate, create an aggregate. This, to me, would be a red flag in a code review.
# make 8 random aliens
@lifeforms = map { RandomSpaceTraveller->new(); } (0..8);
# find out who is klingon
@klingons = grep { $_->get_species() eq 'klingon' } @lifeforms;
# blow the klingons away
foreach (@klingons) { $kirk->shoot_at($_); };
As evidenced above, I disagree. There are those of the functional school (of which I am quickly becoming a convert), who would say mixing OO and functional concepts in the same program is extremely funky in a good way.
Another point -- What if you are implementing an aggregate? Well, you need to know how to dance in aggregate school.
| [reply] [d/l] |
|
|
| [reply] |
|
|
|
|
|
|
|
So, in your example, the aggregate would be of the RandomSpaceTraveller objects, right? Personally, assuming there's nothing more to your example, I would write that as:
$kirk->shoot_at( $_ ) for
grep {
$_->get_species eq 'klingon'
} map {
RandomSpaceTraveller->new
} 0 .. 8;
If you're implementing an aggregate ... we already have a perfectly good aggregate - it's called an array. If you need a named aggregate, use a hash. How does this additional indirection benefit us?
------
We are the carpenters and bricklayers of the Information Age.
Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose
| [reply] [d/l] |
|
|
|
|
|
|
|
dragonchild,
What benefit does this provide?
You really have me there. The person asking for this didn't say why they needed/wanted it. The only benefit I can see to my first solution is that it saves you a lot of typing if you are using it all over the place. By sticking all the objects in an array, as you have shown, you get the same shorthand as if you stuck them all in a new object. I will be sure to pass this along.
Cheers - L~R
| [reply] |
Re: Method Calls on multiple objects
by Kanji (Parson) on Mar 27, 2004 at 02:57 UTC
|
On the error checking front, you may want to throw can into the mix, so methodname is only called if the object implements it.
sub MultiMethod {
my $method = shift;
my $args = shift;
foreach my $object (@_) {
$object->$method(@$args) if $object->can($method);
}
}
| [reply] [d/l] |
|
|
->can isn't effective for checking methods handled by AUTOLOAD.
| [reply] |
|
|
| [reply] [d/l] |
|
|
|
|
sub generate_method
{
my $self = shift;
my ($name) = @_;
my $method = <generate method and put into namespace>;
return $method;
}
sub can
{
my $self = shift;
my ($name) = @_;
if ( <some rule that determines when a method is handled by AUTOLO
+AD> )
{
return $self->generate_method($name);
}
$self->SUPER::can($name);
}
sub AUTOLOAD
{
my $name = our $AUTOLOAD;
$name =~ s/.*::([^:]+)$/$1/;
my $self = shift;
if ( <some rule that determines when a method is handled by AUTOLO
+AD> )
{
return $self->generate_method( $name )->(@_);
}
$self->SUPER::AUTOLOAD( @_ );
}
Now it is ... kinda. It's slower and annoying, but can be done.
------
We are the carpenters and bricklayers of the Information Age.
Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose
| [reply] [d/l] |
Re: Method Calls on multiple objects
by adrianh (Chancellor) on Mar 27, 2004 at 16:52 UTC
|
So how would you do it? Keeping in mind that you want it to be re-useable and as user friendly as possible.
One of my favourite answers (right up there with "yes and no") - it depends ;-)
If there is a natural aggregate object then that's the appropriate place for the behaviour to sit. If there isn't a natural aggregate object then I'd just use for directly.
Having a special object or subroutine just to encapsulate a normal perl idiom would seem overkill, unless it would naturally form part of your object model.
| [reply] [d/l] |