Object oriented programming is an amazing idea according to the textbooks but they have a hard time explaining why. In fact, most don’t even bother to argue the point and instead take it as a given.
This attitude made it popular in books and other teaching materials but not so popular with actual programmers. You don’t often hear about great programs written the OOP way and the most common cases of OOP use in the wild is little more than structured types with functions that work on them.
I’ve been recently working on bbs.tcl where I found myself using a lot of OOP features to great effect. While theoretically possible, I doubt I could have achieved much if I had to use some other paradigm. Although, granted, I was using quite advanced features of TclOO that aren’t present in most other programming languages.
This practical experience with using OOP helped me a lot, which made me realize how much it’s lacking from texts meant to teach it. In fact, texts that otherwise teach programming concepts well fail at describing OOP properly, barely managing to cover the surface technical details. For example, in Intermediate perl, in chapter 10 “Practical reference tricks” has the following problem:
As the Professor tries to maintain the community computing facility (built entirely out of bamboo, coconuts, and pineapples, and powered by a certified Perl-hacking monkey), he continues to discover that people are leaving entirely too much data on the single monkey-powered filesystem, so he decides to print a list of offenders.
The Professor has written a subroutine called ask_monkey_about, which, given a castaway’s name, returns the number of pineapples of storage they use. We have to ask the monkey because he’s in charge of the pineapples. An initial naïve approach to find the offenders from greatest to least might be something like:
my @castaways = qw(Gilligan Skipper Professor Ginger Mary Ann Thurston Lovey); my @wasters = sort { ask_monkey_about($b) <=> ask_monkey_about($a) } @castaways;
In theory, this would be fine. For the first pair of names (Gilligan and Skipper), we ask the monkey “How many pineapples does Gilligan have?” and “How many pineapples does Skipper have?” We get back two values from the monkey and use them to order Gilligan and Skipper in the final list.
However, at some point, we have to compare the number of pineapples that Gilligan has with another castaway as well. For example, suppose the pair is Ginger and Gilligan. We ask the monkey about Ginger, get a number back, and then ask the monkey about Gilligan. . . again. This will probably annoy the monkey a bit, since we already asked. But we need to ask for each value two, three, or maybe even four times just to put the seven values into order.
This can be a problem because it irritates the monkey.
This is a fictional but practical problem. In real life there would be an actual file system, and the monkey would be an operating system which might not get irritated at the constant requests, but waiting for an answer every time might definitely be waistful.
Now, in chatper 13 “Introduction to objects”:
Obviously, the castaways can’t survive on coconuts and pineapples alone. Luckily for them, a barge carrying random farm animals crashed on the island not long after they arrived, and the castaways began farming and raising animals.
Starting with the Animal distribution we created in the previous chapter, we add some specific animals with module−starter:
% module−starter −−module=Cow,Horse,Sheep
Now we have three extra files in lib: Cow.pm, Horse.pm, and Sheep.pm. In each of those files, we’ll add a speak subroutine that’s special to that animal. Although we build up these files piece by piece, we can look at the end of this chapter to see the complete code for each file as they would be after all of our changes.
What are those modules for? They already have the animals, they can hear them speak without any computer programs, object oriented or otherwise. What’s the problem they need solving? Well, there’s none. The goal is to show how OOP in perl works, not how it should be used. BUt how and when to use OOP features should be the goal, it’s the important part. how it technically works is easy enough to learn along the way.
Instead, this is just another common example of “programming objects are just real-life objects” idea, that sounds attractive in books but only confuses in actual situations. People start asking meaningless questions like should Circle inherit from Ellypse or the other way around instead of thinking about components passing messages between each other.
Some might say that OOP is meant for “big programs” and a book like “Intermediate perl” can’t fit such an example. I’d write a whole paragraph about snakeoil merchants and faux-religious leaders and gurus using this exact reasoning to justify why whatever they’re selling doesn’t live up to expectations, but instead I’ll give a counter-example:1
The castaways have discovered other islands nearby, and they’d like to get in contact with them. They found out that some of the islands use IP over avian carriers as specified in RFC-1149 while others use a novel protocol called flarenet.
At first the crue made 2 modules for communication:
Net::Bird
and Net::Flare
. They could be used
like this:
use Net::Bird;
Net::Bird::send("some.island:80", "Hello!");
print Net::Bird::receive(":80");
use Net::Flare;
Net::Flare::flare("32,4", "We need help!");
my $msg = Net::Flare::watch(":80");
print "We got a message: $msg. Help is on the way!\n";
Sometimes it’s necessary to send the message to different islands, some of which use RFC-1149 while others use flarenet. If we have a hash like this:
my %recipients = (
'bird', address => 'some.island:80'},
someisland => {proto => 'flare', address => '32,4'},
anotherisland => {proto => );
We could do something like this:
my $msg = 'Something important';
for(keys %recipients) {
my ($proto, $address) = @recipients{$_}->{'proto', 'address'};
if($proto eq 'bird') {
net::Bird::send($address, $msg);
else {
} Flare::flare($address, $msg);
net ::
} }
That’s a lot of typing, and doesn’t look good. There are many places where this exact if statement might be used. We could move it into a subroutine, but other issues remain. What if he cthulhu-worshipping cultists from another island insisted on only using chaosnet to communicate with everyone else?2 You’d need to change the subroutine, and every subroutine that wraps such a function. Fortunately, there’s a better way. (continue the example yourself, I’m not your ghost writer).