in reply to Object Terminology
(Note: if you've not heard the term "shaggy dog story", here's a short description -- and I don't claim that mine is even remotely humorous)
Nice work. ++. And here's some food for thought for programmers on some of the strength and limitations of those features that are built into Perl (thus leaving off discussion of mixins and traits).
Single inheritance avoids problems with confusing inheritance issues (e.g., which class did that method come from?) and some obscure composition issues which are detailed more carefully in the original traits paper. It's simple to use, but it leads to problems with code duplication. For example, you have a Mammal class and you want to instantiate a Tiger, which just happens to be a subclass from Mammal. All is well and good. However, you're a deviant terrorist version of Siegfried and Roy and you want to create an exploding tiger. In this case, you have a Bomb class and you think your Tiger isa Bomb in addition to a Tiger. Unfortunately, you programming language doesn't support multiple inheritance so you just cut and paste the code. Now you have code duplication. Bad.
One method that Java uses to get around this is the interface. If a class implements an interface, then that class must implement the methods described in that interface. You could create a Bomb interface and that would ensure that all classes that implement bomb would have an explode method, but that wouldn't solve the code reuse problem.
With multiple inheritance, like we have in Perl, you can state this:
package Tiger; use base qw(Mammal Bomb);
Now let's say that mammal inherits from LifeForm, so your class heirarchy looks like this:
LifeForm | Mammal Bomb \ / Tiger
This looks fine, but what you, the deviant Siegfried and Roy didn't know, is that the creator of LifeForm took into account stories of spontaneous human combustion and build an explode method directly into the LifeForm class. What happens? When you call $tiger->explode, &Tiger::explode is not found, but this is OO programming! The @ISA tree is searched leftmost, depth first. Thus, Perl looks for &Mammal::explode and doesn't find it. Then it looks for &LifeForm::explode, finds it and calls it. Bomb::explode is never called. Unfortunately for you, this is a rather weak explosion that simply consumes your Tiger in fire. Most disappointing.
You can get around this by rearranging the order of classes in your use base ... statement, but what if Bomb now implements a method that you need from Mammal? You have the same problem. Yet another way of dealing with this problem is to have this method:
sub Tiger::explode { my $self = shift; $self->Bomb::explode; }
That works, but now we've encoded implementation information directly into our class and made it less flexible. This directly contravenes some of the benefits that we expect from OO programming.
Delegation, on the other hand, neatly avoids all of these problems. In your Tiger constructor, let's assume that you have a _bomb slot. This slot will contain a bomb object. Later, when you wish to explode, you do this:
sub new { my ($class, $data) = @_; # deliberately simplistic! $data->{_bomb} = Bomb->new; bless $data, $class; } sub Tiger::explode { my $self = shift; $self->{_bomb}->explode; }
With this, we explicitly call the method we want, as in the $self->Bomb::explode call above, but we limit the knowledge of which class we are using in one spot (in this case, in the constructor).
On the surface, this might not seem like much of a win, but what happens if this is more complicated and we have four methods we need from our Bomb class?
sub set_timer { my $self = shift; $self->Bomb::set_timer; } sub light_fuse { my $self = shift; $self->Bomb::light_fuse; } sub explode { my $self = shift; $self->Bomb::explode; } sub disarm { my $self = shift; $self->Bomb::disarm; }
Now we have a problem. Without delegation, if we gained a conscience and wanted to change the Bomb to a Toy::Bomb, we have multiple places that we would need to change the class name. With delegation, we only have one place to change it and the delegated methods don't change.
Another benefit of delegation is that you are relying only on the published implementation. With inheritance, you must comply explicitly with the inherited implementation and (particularly with Perl), if private methods change, you might accidentally step on them. You are also more likely to be forced to use the parent class implementation. If the parent class uses a blessed hashref, you will use a blessed hashref whether you want to or not. Delegation decouples the implementation from the Bomb and Mammal implementation, with the exception of the implied contract that "this interface will not change". The major drawback of delegation, though, is that it can often take more work to set up. You can't inherit the methods that you want, so you have to explicitly create them.
As any competent manager will tell you, delegation is the preferred method for dealing with exploding tigers.
Cheers,
Ovid
New address of my CGI Course.
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: Re: Object Terminology (and an awful shaggy dog story)
by stvn (Monsignor) on Jan 12, 2004 at 17:53 UTC |