I wasn't an OO proponent until recently. Perhaps I'm not really even
a good one now. I did my fair share of OO classes when I was studying
at university and I knew the concepts pretty well. Both of my major
team projects involved writing in Visual C++ (oh! the horror!) and I
was pretty o'fay with classes and objects and methods and all. I knew
how to use objects but I was hazy on their design. What makes an
object? The programming I have had to do doesn't map so well to the
simple examples of "person" classes, or "trucks" with "fire trucks",
"tip trucks" and such inheriting from the "truck" class.
Sure, my 3rd and 4th year projects didn't immediately map into objects
either. It might have been a useful learning exercise if I'd been on
the design teams, but I would have slowed things down. Taking a
requirements specification and turning out a list of objects and how
they'll interact was magic so far as I could tell.
I didn't learn Perl OO until I had to look for work. It had always
seemed too hard before then. It took me 30 minutes to read all the
relevant stuff from Damian's book. It looked easy. It was.
After doing some simple introductory projects at my new job, I was set
loose on "The Project". Well coded... well mostly well coded but
it had 1 object and about 1000 functions full of if/else statements.
If my type is a subnet do this. Else if my type is a host do that.
Else if my type is a domain do something else...
Even I could see that there should be either a heap more specialized
functions or a lot more specific objects. So I asked if we could
change it, and of course was told "no". It worked as it was. So I
"maintained" The Project and secretly started to modularize it a bit
better. Then another developer, slightly higher in the hierarchy than
I, found that a feature request was impossible to provide in the system
as it stood. We started to write more specific objects (subnet, host,
domain etc), all inheriting from the initial monster... Hooray!
After working on this project I suddenly understood both Perl OO and
general OOD much better. I got a good feel for what kind of
functions should be generic and which should be specific. I started
thinking more in terms of OO. I started proposing OO solutions to
things, even here because they seemed to be better solutions
than otherwise.
Then BUU asked a question and I found myself responding
"Do consider OO where it might be useful". But what does
that mean? If someone had said that to me before I worked on The
Project I doubt I would have had a good idea of where OO would be
useful at all.
Computer Science classes had taught me the platitudes:
- Use OO for data encapsulation
- Use OO whenever you have things that belong together
- Use OO to provide a consistent interface even when the
underlying implementation changes
but these never really helped me. In a CGI project what's a "useful" use of OO? The answer is, it depends.
So I begin to think that it might be helpful to look at WHY I thought
an OO solution to vaevictus's problem was a good idea.
Firstly it seemed obvious to me that a solution involving an array of
hashes would work. So I created one to play with. The requested push
function took my array and did stuff to it, likewise my pop function.
Then I looked at it again and thought, this function is very specific
to this data structure. Nothing else could be passed to this function
and have a sensible result. It seemed that it would be nice to save
the programmer from assuming that these just replaced push and pop.
And I was passing the array around, how could I stop the programmer
from messing up it's order and then wondering why the pop
function didn't give the next event? Could I make it so this code could be
useful to other programs too?
It seemed like this event handling was a really good thing to
modularize. When a lot of OO Perl programmers think of modules they
immediately think of objects. Not me. I usually think of libraries.
Then that second last concern up there started niggling at me. How
could I hide the internals of the event queue from the programmer? OO
of course. I'd even stopped thinking of it as "an array" and started
thinking of it as "an event queue". It wanted to be an object. So it
was.
Of course the use of a single object in a Perl project doesn't
automatically require that the rest of your code be broken up around
objects. Many of us work with CGI in an OO sense every day yet write
largely imperative scripts.
Findy Services and B. Jacobs
don't have it all wrong when they criticize OO. It's not a magical
solution. But it can be very, very useful.
So here are my guidelines for indications that you might want to use
objects, even in otherwise imperative programs.
- Create an object when you have a number of functions that
all work exclusively on the same data type and would return errors or
meaningless results on anything else.
- Create an object when your data type must not have its
internals messed about with by the object user.
- Create an object when it's easier to think of a collection
of data as a unit instead of thinking of its structure.
- Create a number of objects when you find yourself writing
many different subroutines with the same basic purpose to work on
slightly different data (eg. read_data1, read_data2, read_data3,
process_data1, process_data2, process_data3), or huge subroutines with
big cascades of if-then-elses. Polymorphism works great here.
What other suggestions do people have?
jarich
(Revelation) Re: Where/When is OO useful?
by Revelation (Deacon) on Jun 21, 2002 at 06:57 UTC
|
Using OOP:
Personally, I find object oriented programming to be most useful when coding for abstraction, and structure. Object oriented programming is a much more serious commitment, that programming in general, because I find myself more committed to revision, optimization, and incite into my data. Packages that focus on abstraction, and being useful in many situations seem to be easier to write, as well.
Object oriented program seems to go hand in hand with modeling the input data, something that I don't find myself doing most of the time. This goes hand in had with better algorithms, increased efficiency in SQL queries, and consistent data parsed. All this leads to well structured, clean code; usable in the future, and soapy clean.
Data modeling makes us look at the most important factor in our code, the initial data sent to the script. OOP stresses an underlying structure that can deal with this data methodically, and with an inherited structure, forcing a more thorough data analysis, reducing development time, and ensuring more accurate coding. Part of data modeling is 'data hiding,' preventing classes from accessing data meant for their counterparts, allowing for greater security.
OOP allows me to abstract subroutines, optimize quicker, and revise in smaller chunks. Programming for data manipulation, instead of functionality brings structure, and detail into the code earlier in the game. Structure has always been a great virtue in code, and OOP allows me to get to that clean structure that it seems to so elastically bind around.
Adding to the list from my thoughts:
- Use OO when maintainability counts.
- Use OO when structure is lacking, or for abstracting structure. (much like your fourth suggestion.)
- Use OO when logic fails, or has little use, but data manipulation seems to bring us closer to the goal.
- Use OO when you know how to use OO. Don't just go and bless something, and tell us you're OO programming, use it if you know how to manipulate it and the methodology it gives you in programming.
I do not claim to know what I'm talking about :) | [reply] |
A reply falls below the community's threshold of quality. You may see it by logging in. |
Re: Where/When is OO useful?
by Zaxo (Archbishop) on Jun 21, 2002 at 07:11 UTC
|
| [reply] |
Re: Where/When is OO useful?
by rinceWind (Monsignor) on Jun 21, 2002 at 13:21 UTC
|
Some advice for jarich and anyone else dabbling in OO.
Get a book on design patterns. The Gang of Four book is a classic, and many people's bible, but the book is somewhat meaty and not very accessible. There are many simpler books available which explain the patterns in more user friendly language, but most of these have set opinions about one or more favourite patterns, and why they are so important.
An understanding of design patterns will help differentiate between good OOD and bad OOD, and also highlight when OO is appropriate. | [reply] |
|
| [reply] |
Re: Where/When is OO useful?
by kvale (Monsignor) on Jun 21, 2002 at 05:36 UTC
|
Excellent post. I would add the guideline
"Create a class
when you want a resusable perl module with a flexible interface"
Many OO CPAN modules are simplicity themselves to use and modify.
-Mark | [reply] |
|
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] |
|
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] [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] |
Re: Where/When is OO useful?
by jotti (Scribe) on Jun 22, 2002 at 18:27 UTC
|
Quote:
Then BUU asked a question and I found myself responding "Do consider OO where it might be useful". But what does that mean? If someone had said that to me before I worked on The Project I doubt I would have had a good idea of where OO would be useful at all.
Yes, it's like the stupid answer to the question What kind of music do you listen to? "I listen only to good music." or the statement "Good thing that I don't like coffee. It tastes so horrible."
| [reply] |
|
|