in reply to Re^3: Understanding 'Multiple Inheritance'
in thread Understanding 'Multiple Inheritance'

Thank you tilly. Not only have you helped me understand the problem of "tight coupling" vs. inheritance, you have set me on the right path by pointing out the pitfalls in my current path. I will try another tact with my code... encapsulation and information hiding would be worthy causes to pursue, I don't even know how I can do that when multiple classes are involved without resorting to multiple inheritance.

In any case, this has been an instructive thread, if I may say so myself.

--
when small people start casting long shadows, it is time to go to bed
  • Comment on Re^4: Understanding 'Multiple Inheritance'

Replies are listed 'Best First'.
Re^5: Understanding 'Multiple Inheritance'
by jhourcle (Prior) on Mar 08, 2005 at 13:27 UTC

    I think you're viewing inheritance as the solution without fully understanding just what the implications are. (which is what your original post hinted at). I'll try to explain it simply:

    When you inherit, you make the other module's methods available to whomever might be using your module. When you multiply inherit, you make all methods from all inherited modules available, which may cause interaction problems.

    Typically, when you're looking at when you use inheritance, you look for is-a relationships, rather than has-a relationships. In your particular case, it looks to me as if the IMAP::Client relationship is shaky. (if you want to it almost identically to an IMAP::Client, then it's an is-a relationship. If you want the user of your program to not deal with the IMAP::Client directly, then it's a has-a relationship. It look as if the relation with Config::Simple is definately has-a. Here is the basic logic to deal with the has-a relationships:

    package MyPackage; use strict; use IMAP::Client; use Config::Simple; use Carp; sub new { my $class = shift; return bless {}, ref($class) || $class; } sub load_config { my $self = shift; $self->{'config'} = Config::Simple->new(@_); return $self->{'config'}; } sub connect_to_imaphost { my $self = shift; my $config = $self->{'config'} or croak "ERROR : Connect to imaphost without loading config"; $self->{'imap'} = Mail::IMAPClient->new( Server => $config->{'IMAP_HOST'}, User => $config->{'EM_UNAME'}, .... ); return $self->{'imap'}; } # accessor functions sub imap { return shift->{'imap'}; } sub config { return shift->{'config'}; }

    Now, when you want to use your module, you can do something like:

    use MyPackage; my $pkg = MyPackage->new(); $pkg->load_config('my.conf'); $pkg->connect_to_imaphost();

    And should you need to access the underlying objects:

    my $msg_count = $pkg->imap()->message_count( ... );

    (You don't want to store the return from $pkg->imap() for long term storage, in case the system has to disconnect/reconnect, or something else that change the IMAP::Client object that is associated with your MyPackage object.)