tags:

views:

83

answers:

2
package a::b::c:d

my $res =  a::b::c:e->new(); # i am doing like this
# is there any othere to do this

sub new {
...
 my $self = { 
     #result = a::b::c:e->new();
  }
}

sub test {
}

sub test2 {
}


1;

package a::b::c:e

sub new {
...
}

sub testresult {
}
1;

My question is:

  • how to initalize the e module in d in new itself rather creating every function and

  • how to use that to store some results into e:testresult

+2  A: 

There are two strategies -- either examine the symbol table to initialize on creation, or make use of AUTOLOAD and test with can. AUTOLOAD can be messier as you have to deal with the case where the method isn't there:

sub AUTOLOAD {
    my $self = shift;

    my $method = $AUTOLOAD;
    $method =~ s/.*://;   # strip package name

    if ( $self->{'result'}->can($method) ) {
        return $self->{'result'}->$method(@_);
    } else {
        croak "Unknown method : $method";
    } 
}  

But the symbol table trick is brittle, as if they're using inheritance, you won't see the inherited methods without walking up @ISA, too. (and even if they're not -- they might start using inheritance in the future, which results in things breaking)

...

Typically, when you're trying to copy another module's interface, you've got a case of inheritance, so you might want to ask yourself what the relationship is between ::d and ::e :

  • a::b::c::d is an a::b::c::e
  • a::b::c::d uses a::b::c::e

If it's an is-a relationship, it's typically better suited to inheritance (although you might have wrappers around each of the methods, and still need to go through this whole exercise anyway). If it's a uses relationship, odds are you don't want to inherit from every last method they have, and can just hard code a list (although, the list might change if the used class is updated)

foreach my $method ( @list_of_methods_to_copy ) {
    *{$method} = sub {
        my $self = shift;
        return $self->{'results'}->$method(@_);
    }
}
Joe
am i asking this ? but any thanks :-)
Tree
I assumed so, based on 'rather creating every function'. If this isn't what you're asking for, could you give some specific examples of what you're trying to do? (how you expect to be able to interact with it, etc.)
Joe
A: 

Provided that you're not looking for inheritance between the two classes, it looks to me that you might want to use Class::Delegator for composing your class. That way, you can create the delegation routines by putting the following in a::b::c::d.

use Class::Delegator send => 'testresult', to => '{result}';

But you'd need to fix your constructor anyway:

my $self 
    = bless { 
        result => a::b::c::e->new()
    }, $class_name
    ;
return $self;

Having done that, you'd have a field '{result}' to delegate to.

Axeman