Overloading/Inheritance issue

Regan Heath regan at netmail.co.nz
Fri Aug 3 01:25:13 PDT 2007


Steve Schveighoffer wrote:
 > Regan Heath Wrote:
 >> So, as you can see it's not for performance reasons but rather to
 >> avoid obscure bugs which when they manifest do so silently.
 >
 > My argument is not against this, as you will note that in these
 > examples, both base and derived classes can match the call by some
 > sort of implicit conversion.  In the case where both the base class
 > and the derived class  match the call, I could care less if the
 > derived class was called instead of the base class.

But, that's exactly the problem.

In fact example 2 shows that we currently have the undesirable and buggy 
behaviour in the current D implementation, eg.

import std.stdio;

class B
{    long x;
      void set(long i) { writefln("B::set(long)"); x = i; }
      void set(int i)  { writefln("B::set(int)"); x = i; }
      long squareIt()  { writefln("B::squareit()"); return x * x; }
}
class D : B
{
      long square;
      void set(long i) { writefln("D::set(long)"); B.set(i); square = x 
* x; }
      long squareIt()  { writefln("D::squareit()"); return square; }
}

long foo(B b)
{
     b.set(3);
     return b.squareIt();
}

void main()
{
     writefln(foo(new D));
}

Output:
B::set(int)
D::squareit()
0

In the above example the object is actually of type 'D' but the method 
is called from a reference to a 'B'.  The result is a call to 
B::set(int), instead of D::set(long) and then D::squareit() which fails 
utterly.

This is an 'obscure' bug because it is happening silently.

It seems example 2 either no longer behaves as it did when it was first 
posted (D has changed) or it was never a correct example for the problem.

 > I am proposing a change of behavior when the derived class CANNOT
 > match the call.  At that point the compiler errors out instead of
 > examining the base classes.  When the coder writes code where there
 > is only one match, and that match is in a base class, it makes
 > perfect sense that the coder explicitly wants to call the base class'
 > method.  I see no reason to force the coder to explicitly call for
 > the base class' method when there is no alternative in the derived
 > class, the code is unambiguous.

I see the distinction, and it is the case with your original example as 
you wanted it to call select() from the base class.

Interestingly, if the derived class "EpollSelector" had to conform to 
the interface "ISelector" that the base class "AbstractSelector" 
implements then the author of "EpollSelector" would have noticed and 
added the 'alias' and this would never have come up.

This change you suggest does violate D's current 'simple' lookup rules 
and go against the original reasoning of:

"His argument is that one can easilly miss an overload of f() somewhere 
in a complex class heirarchy, and argues that one should not need to 
understand everything about a class heirarchy in order to derive from it."

So, if you want to see this change you're going to have to post 
something convincing addressing this, probably with some real-life examples.

 > I'd bet we'd see 0 obscure bugs if this change was made ;)   As I've
 > mentioned, I've already seen one obscure bug caused by the current
 > implementation...

Not to nit pick but is the bug you're referring to the problem you had 
with Tango's tango.io.selector.EPollSelector?  If so I wouldn't say that 
bug was 'oscure' because presumably it gave you an error on compile, as 
opposed to silently failing on some customers system which is what 
happens in the two examples given by Walter (including example 2 above 
which fails in D today).

Regan



More information about the Digitalmars-d mailing list