How should overruling of overloaded functions work?
nobody
nobody at mailinator.com
Sun Aug 20 08:56:23 PDT 2006
Søren J. Løvborg wrote:
> See for instance, "Why extends is evil" at JavaWorld, discussing the
> "fragile base-class" problem.
> http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html
That article was horrible. It sounds plausible that safe changes in a base class
might have undesired effects on a derived class but I would need an example. All
his examples ignored the stubs of the base class. Big surprise ending -- he
fixes the problem of ignoring the stubs of base classes with an interface.
He says "whenever I violate a central OO principle like *implementation hiding*,
I end up rewriting that code." Yet the article is really about subtle variations
of failing to hide implementation. So subtle in fact that the author did not
even realize the problem:
class ObviousProblem
{
public DataStore data;
}
class SubtleProblem extends DataStore
{
// does not override /any/ DataStore methods
}
Now we have:
ObviousProblem o = new ObviousProblem();
o.data.invalidate();
SubtleProblem s = new SubtleProblem();
s.invalidate();
In short extending a class just because you are using it as a backing store is a
bad idea. A big clue that is-a does not hold is when not a single one of your
base class' methods make sense for the derived class. Yet despite adding and
removing random elements makes no sense for a Stack his example is:
class ArrayList
{
public void add( int i, Object o ) { }
public Object remove( int i ) { }
public void clear() { }
}
class Stack extends ArrayList
{
public void push( Object article )
public Object pop()
public void push_many( Object[] articles )
}
Now translating that to a more obvious example an implementation hiding failure:
class StackEquivalent
{
public ArrayList data;
public void push( Object article )
public Object pop()
public void push_many( Object[] articles )
}
Using /any/ of ArrayList's functions on a Stack object will invalidate it. Not
just clear(). The /exact/ same situation applies to StackEquivalent.
Now the second implementation hiding failutre is not about exposing more than
one needs but rather less:
class Stack
{
public void push( Object article )
public Object pop()
public void push_many( Object[] articles )
}
class Monitorable_stack extends Stack
{
private int high_water_mark = 0;
private int current_size;
public void push( Object article )
{ if( ++current_size > high_water_mark )
high_water_mark = current_size;
super.push(article);
}
public Object pop()
{ --current_size;
return super.pop();
}
public int maximum_size_so_far()
{ return high_water_mark;
}
}
What jumps out when you just look at the function stubs for base and derived is
that Monitorable_stack chose not to override push_many. It certainly is one of
the functions you ought to be interested in intercepting.
The only plausible conclusion is that an inference has been made about Stack's
hidden implementation. It turns out that was exactly the reasoning behind the
article's author. Yet again has to violate "a central OO principle like
implementation hiding" in order to make his point.
Given the pattern that all his examples ignored the stubs of the base class one
can only conclude that he needs to use interfaces to be able to think clearly
about what certain classes expose. If it works for him then I am happy he
figured it out. However his stub blindness has nothing fundamental to do with
inheritance. In short I suspect he has misinterpreted "The fragile base-class
problem".
More information about the Digitalmars-d
mailing list