Design choice: subclassing or "supplementing"

J

J Krugman

I have this class from CPAN (let's call it, creatively enough, Foo)
that suits me fine in almost every respect, except for one workhorse
method (say, bar) that I think could be significantly enhanced.
One possibility would be to create a subclass MyFoo of Foo just
for the purpose of overriding bar. Alternatively, I could have a
file FooSupplement.pm, in which I do something like

use strict;
use warnings;
package Foo;
{
no warnings 'redefine';
sub bar {
# raise the bar to perfection
}
}
1;

Then, instead of using some subclass MyFoo, I use good ol' Foo
followed by "use FooSupplement".

I *suppose* (please correct me if I'm wrong) that this is yet
another one of those choices that boils down to personal preference,
but I'd love to take a very informal poll on what programmers here
would typically prefer to do in such a situation.

TIA,

jill
 
D

David K. Wall

J Krugman said:
I have this class from CPAN (let's call it, creatively enough,
Foo) that suits me fine in almost every respect, except for one
workhorse method (say, bar) that I think could be significantly
enhanced. One possibility would be to create a subclass MyFoo of
Foo just for the purpose of overriding bar. Alternatively, I
could have a file FooSupplement.pm, in which I do something like
[redefining a method instead of subclassing and overriding it]

I'm no OOP guru, in fact I'm a downright novice at OOP, so keep that
in mind.

Subclassing and overriding the method seems to me the better way.

If you simply redefine the method, then someone reading your code
might look at the docs for Foo.pm and then wonder why bar() is not
functioning as documented. Yes, they should have looked at the docs
for FooSupplement as well, but why look there for a method for a Foo
object?

If you subclass, then your "main" program says 'use MyFoo;' and the
maintenance programmer knows to look at MyFoo.pm instead of Foo.pm.
Once there, it's obvious you're subclassing because the first thing
there is

package MyFoo;
use base 'Foo';

And, of course, you've documented everything in pod and perhaps in
comments as well.
 
A

Anno Siegel

J Krugman said:
I have this class from CPAN (let's call it, creatively enough, Foo)
that suits me fine in almost every respect, except for one workhorse
method (say, bar) that I think could be significantly enhanced.
One possibility would be to create a subclass MyFoo of Foo just
for the purpose of overriding bar.

Overriding base class methods is more than just replacement. If
the base class uses the overridden method internally, it will call
the *overriding* method on objects from your (inheriting) class.
This is what allows old code to call new code in OO, and it is at the
heart of inheritance.
Alternatively, I could have a
file FooSupplement.pm, in which I do something like

use strict;
use warnings;
package Foo;
{
no warnings 'redefine';
sub bar {
# raise the bar to perfection
}
}
1;

Then, instead of using some subclass MyFoo, I use good ol' Foo
followed by "use FooSupplement".

Boo!

That's called "intrusion into Foo's living-room", and in languages less
forgiving than Perl you can get shot for that. Perl allows it, but
it's only for emergencies, not for regular programming.
I *suppose* (please correct me if I'm wrong) that this is yet
another one of those choices that boils down to personal preference,
but I'd love to take a very informal poll on what programmers here
would typically prefer to do in such a situation.

I don't think it is a matter of much choice. If you can do what you
need to do via inheritance, go that way. You need very good reasons
to change into someone else's name space, and you'd limit the access
to the absolute minimum. I don't think you have such a situation.

Anno
 
J

J Krugman

Overriding base class methods is more than just replacement. If
the base class uses the overridden method internally, it will call
the *overriding* method on objects from your (inheriting) class.
This is what allows old code to call new code in OO, and it is at the
heart of inheritance.

That's called "intrusion into Foo's living-room", and in languages less
forgiving than Perl you can get shot for that. Perl allows it, but
it's only for emergencies, not for regular programming.
I don't think it is a matter of much choice. If you can do what you
need to do via inheritance, go that way. You need very good reasons
to change into someone else's name space, and you'd limit the access
to the absolute minimum. I don't think you have such a situation.

Many, many thanks. I was definitely heading in a bad direction
there.

jill
 
D

David K. Wall

Abigail said:
David K. Wall ([email protected]) wrote on MMMDCCCLXXIV September
MCMXCIII in <URL:()
() > I have this class from CPAN (let's call it, creatively enough,
() > Foo) that suits me fine in almost every respect, except for one
() > workhorse method (say, bar) that I think could be significantly
() > enhanced. One possibility would be to create a subclass MyFoo of
() > Foo just for the purpose of overriding bar. Alternatively, I
() > could have a file FooSupplement.pm, in which I do something like
() [redefining a method instead of subclassing and overriding it]
()
() I'm no OOP guru, in fact I'm a downright novice at OOP, so keep that
() in mind.
()
() Subclassing and overriding the method seems to me the better way.
()
() If you simply redefine the method, then someone reading your code
() might look at the docs for Foo.pm and then wonder why bar() is not
() functioning as documented. Yes, they should have looked at the docs
() for FooSupplement as well, but why look there for a method for a Foo
() object?

I don't buy that argument. Why would someone reading your code and
wanting to look up the documentation for 'bar()' in Foo.pm?

I was thinking of bar() as a method for an object of class Foo. Given that
assumption (which I carelessly didn't state explicitly), Foo.pm should be
the obvious place to look for its definition, right?
The code
contains a call to a function 'bar()', which turns out not to be
defined in the file. The code also uses two classes.

Two? Foo and what else? Unless I'm mistaken, FooSupplement.pm doesn't
create a new class, it just redefines one of the Foo methods, namely bar().
I'd say any programmer that just ignores 50% of the inherited modules,
and only searches the documentation for the other half deserves what
he gets.

I agree completely.
() If you subclass, then your "main" program says 'use MyFoo;' and the
() maintenance programmer knows to look at MyFoo.pm instead of Foo.pm.

But in the given example, the code says "use FooSupplement". So, why
*wouldn't* the maintainance programmer look there (which he doesn't
according to you)?

No reason at all. A competent maintenance programmer *would* look at
FooSupplement. I just don't think it's the *obvious* place to look for a
method for a Foo object. Why do something in a non-obvious way when there's
an obvious way -- subclassing and overriding -- to achieve a similar
effect? That's all I meant, though I'll readily admit I could have stated
it more clearly.

Apologies for the long delay in getting back to this thread.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top