www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - Strange results overriding interface return with class return

Using DMD 0.118, Windows 98SE.

This was briefly talked about before, but not actually reported as a 
bug.  It's a separate issue from the other interface covariance bug I 
reported a while back.

digitalmars.D.bugs/1726

The compiler allows a method with an interface return type to be 
overridden with a class return type.  However, when this is done, 
strange things happen, from AVs to doing things that seem to have no 
relation to the method that was called.

Two similar testcases:

----- covariant_int2.d -----
import std.stdio;

interface Father {}

class Mother {
     Father test() {
         writefln("Called Mother.test!");
         return new Child(42);
     }
}

class Child : Mother, Father {
     int data;

     this(int d) { data = d; }

     override Child test() {
         writefln("Called Child.test!");
         return new Child(69);
     }
}

void main() {
     Child aChild = new Child(105);
     Mother childsMum = aChild;
     Child childsChild = aChild.test();
     Child mumsChild = cast(Child) childsMum.test();
}

----- covariant_int4.d -----
import std.stdio;

interface Father {
     void showData();
}

class Mother {
     Father test() {
         writefln("Called Mother.test!");
         return new Child(42);
     }
}

class Child : Mother, Father {
     int data;

     this(int d) { data = d; }

     override Child test() {
         writefln("Called Child.test!");
         return new Child(69);
     }

     void showData() {
         writefln(data);
     }
}

void main() {
     Child aChild = new Child(105);
     Mother childsMum = aChild;

     aChild.test();
     Father mumTest = childsMum.test();
     aChild.showData();
     mumTest.showData();
}

----------
D:\My Documents\Programming\D\Tests\bugs>covariant_int2
Called Child.test!
Called Child.test!
Error: Access Violation

D:\My Documents\Programming\D\Tests\bugs>covariant_int4
Called Child.test!
Called Child.test!
105
Child
----------

I'm guessing that the underlying cause of both is the same - as 
speculated before

digitalmars.D.bugs/2070

interface references aren't compatible with class references.  This 
means that when a method is covariantly overridden from interface to 
class, and it is then called through the base class, a class reference 
is returned, which is no good as the base class method, and hence the 
caller through it, needs an interface reference.

The spec doesn't explicitly forbid this, but if it isn't supposed to 
work then the compiler should be giving an error (and the spec updated 
accordingly).  Otherwise, it could be fixed to work like this:

- The compiler would detect that a method is being overridden from 
Father (interface) to Child (class), and compile Child.test to return an 
interface reference for compatibility

- When the method is called through a Child reference, the caller would 
need to implicitly convert the returned Father reference to a Child 
reference.  Of course, this conversion can be optimised away if the 
context dictates that a Father reference is required.

- It would be necessary to throw in a restriction or two.  A class 
cannot derive from both a class and an interface, or multiple 
interfaces, if they define methods with the same name and parameter 
types but one has a class return and the other has an interface return. 
  Assuming that it would be impossible to compile the method to be 
compatible with both simultaneously.

I haven't experimented with interface-to-interface covariant overrides, 
so don't know if these work.  But I can imagine there being 
complications when multiple interface inheritance is involved.

The question: Is it worth making this work?  Or do these complications 
mean that we ought to disallow interface-to-class overrides altogether?

Stewart.

-- 
My e-mail is valid but not my primary mailbox.  Please keep replies on 
the 'group where everyone may benefit.
Mar 21 2005