Many OO CPAN modules are simplicity themselves to use and modify.
I don't agree. I think many OO modules are hard
to modify - the latter meaning "subclass".
Here's coding problem.
Someone has written a BaseballPlayer class, to
maintain statistics of players. Your task is to subclass
it to create a BaseballPlayer::Pitcher class so
the additional statistics for pitchers can be dealt with.
Where are you going to store your instance data?
If you answer "in the hash returned by the constructor of
the BaseballPlayer class", or "in whatever object the superclass
uses", or "that depends on how the BaseballPlayer class is
implemented", you fail the test. And why do you fail? Because
you are breaking the basic concept of object orientness:
encapsulation. It shouldn't matter how the superclass is
implemented. Unfortunally, Perl doesn't make it easy to use
inheritance. It all works handy-dandy if you can enforce a
certain style, implementation or module usage of the total
inheritance tree, but that isn't usually the case. It wouldn't
be code reuse if you had to write everything yourself, now
would it?
Abigail
| [reply] [Watch: Dir/Any] |
Where are you going to store your instance data?
Since you asked... in a variable outside the object itself: a
closure, in all likelihood. In my experience, this is the best
use for flyweight objects in Perl, far better than as an awkward
method of strong encapsulation. Here is how I'd do it:
#!/usr/bin/perl
use strict;
use warnings;
package BaseballPlayer;
use Carp;
my %attrib;
sub BEGIN {
%attrib = map { $_ => 1 }
qw( RBI Batting_Average Hits Runs Stolen_Bases Games_Played );
no strict 'refs';
for my $n ( keys %attrib ) { *$n = sub { $_[0]->{$n} } }
}
sub new {
my( $class, %arg ) = @_;
exists $attrib{$_} or croak "Unknown stat: $_" for keys %arg;
$arg{$_} ||= 0 for keys %attrib;
bless \%arg, $class;
}
package BaseballPlayer::Pitcher;
our @ISA = 'BaseballPlayer';
{
my %object;
sub new {
my( $class, %arg ) = @_;
my %pitcher_stat = map { $_ => delete $arg{$_} || 0 } qw( ERA Stri
+keouts );
my $base = BaseballPlayer->new(%arg);
my $ret = bless $base, $class;
$object{$ret} = \%pitcher_stat;
$ret;
}
sub ERA { $object{$_[0]}{ERA} }
sub Strikeouts { $object{$_[0]}{Strikeouts} }
sub DESTROY { delete $object{$_[0]} }
}
package main;
my $p = BaseballPlayer::Pitcher->new( Hits => 23, ERA => 4.32 );
print $p->Hits, "\n";
print $p->ERA, "\n";
Likely you have your own solution; if it is significantly different
(or especially if it's better) than mine, do share it. This solution
passes the tests you mentioned, and has become a regular habit for me.
I agree with your point: Perl doesn't make it easy to use inheritance.
This is a wordy, tiresome ritual, and thus is error-prone. Various
aspects of Perl's OO require such rituals, however; personally, I wouldn't
single out inheritance on this account.
Update: Changed $p's ERA to something realistic, upon zdog's
advice.
Update: Simplified my code, upon tye's advice. My inclusion
of needless code was a cargo-cult imitation of my own practices, which
reflected the needs of prior projects. This, I think, underscores my
point about the unfortunate effects of rituals which compensate for the
shortcomings of a language.
| [reply] [Watch: Dir/Any] [d/l] |
package BaseballPlayer::Pitcher; {
use vars '@ISA';
@ISA = 'BaseballPlayer';
my (%ERA, %Strikeouts);
sub ERA : lvalue {$ERA {+shift}}
sub Strikeouts : lvalue {$Strikeouts {+shift}}
sub DESTROY {
my $self = shift;
delete $ERA {$self}, $Strikeouts {$self}
}
}
Abigail
| [reply] [Watch: Dir/Any] [d/l] |
The truth is that ineritance sucks. There are problems where inheritance is a good solution, but most of the time composition is a better method, and not just because it promotes encapsulation. A has-a relationship is just plain easier to code with. Even if your language provides a good mechanism for inheritance (which Perl does not) if your writing a substantial class than you'll find yourself looking under the hood 9 times out of 10.
Cheers,
Erik
Light a man a fire, he's warm for a day. Catch a man on fire, and he's warm for the rest of his life. - Terry Pratchet
| [reply] [Watch: Dir/Any] |