Thread overview | ||||||||
---|---|---|---|---|---|---|---|---|
|
August 09, 2007 Multiple inheritance and covariant return types. | ||||
---|---|---|---|---|
| ||||
Hi, I have another question on multiple inheritance. The following code does not work (tested with DMD 1.020 and 2.003) --- interface A {} interface B {} interface AB: A, B {} abstract class X { abstract A func(); } interface Y { B func(); } class XY: X, Y { AB func() { return null; } } --- The compiler complains about the line 'AB func() { return null; }': t.d(38): function t.XY.func incompatible covariant types A() and B() but I think it should work, because AB is both, an A and a B, so the return type is covariant with both overridden methods. In fact, the example works fine, if X is an interface instead of an abstract class. Is this a bug or is it my mistake? Thanks, Frank |
August 09, 2007 Re: Multiple inheritance and covariant return types. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Frank Fischer | Reply to Frank,
> Hi,
>
> I have another question on multiple inheritance. The following code
> does not work (tested with DMD 1.020 and 2.003)
>
> ---
> interface A {}
> interface B {}
>
> interface AB: A, B {}
>
> abstract class X {
> abstract A func();
> }
> interface Y {
> B func();
> }
> class XY: X, Y {
> AB func() { return null; }
> }
> ---
> The compiler complains about the line 'AB func() { return null; }':
> t.d(38): function t.XY.func incompatible covariant types A() and B()
>
> but I think it should work, because AB is both, an A and a B, so the
> return type is covariant with both overridden methods. In fact, the
> example works fine, if X is an interface instead of an abstract class.
>
> Is this a bug or is it my mistake?
>
> Thanks,
> Frank
The issues is that casting from a class that implements A, B and AB to each of these results in a slightly different result.
IIRC when a class is cast to an interface, what you get is a pointer to a v-table inside of the class (not the normal one). However because AB inherits from A and B, you end up getting two different v-tables. So returning an AB interface instance would give you something that is an AB and might be an A or B but not both. (This is all at the binary level of course)
|
August 09, 2007 Re: Multiple inheritance and covariant return types. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Frank Fischer | Frank Fischer wrote: > Hi, > > I have another question on multiple inheritance. The following code does not > work (tested with DMD 1.020 and 2.003) > > --- > interface A {} > > interface B {} > > interface AB: A, B {} > > abstract class X { > abstract A func(); > } > > interface Y { > B func(); > } > > class XY: X, Y { > AB func() { return null; } > } > --- > The compiler complains about the line 'AB func() { return null; }': > > t.d(38): function t.XY.func incompatible covariant types A() and B() > > but I think it should work, because AB is both, an A and a B, so the return > type is covariant with both overridden methods. In fact, the example works > fine, if X is an interface instead of an abstract class. > > Is this a bug or is it my mistake? > > Thanks, > Frank > It's not a bug. Classes are *convertible* to interfaces that it implements but they are not *covariant* with said interfaces. The same thing happens for an interface and it's super interfaces. The interface is not covariant with is super interfaces, only convertible to them. (exception maybe the first interface). Thus in the example above AB is not both an A and B. This behavior is different than Java and other OO languages, and is so for performance reasons. There are some tricks the compiler does to allows override as if the types were covariant, but it only works in some situations. You can see it for yourself with the following code: interface A {} interface B {} interface AB: A, B {} class ABImpl : AB { } void test() { writefln("%X", cast(void *) ab); writefln("%X", cast(void *) cast(AB) ab); writefln("%X", cast(void *) cast(A) ab); writefln("%X", cast(void *) cast(B) ab); } -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D |
August 09, 2007 Re: Multiple inheritance and covariant return types. | ||||
---|---|---|---|---|
| ||||
Posted in reply to BCS | BCS wrote:
> Reply to Frank,
>
>> Hi,
>>
>> I have another question on multiple inheritance. The following code
>> does not work (tested with DMD 1.020 and 2.003)
>>
>> ---
>> interface A {}
>> interface B {}
>>
>> interface AB: A, B {}
>>
>> abstract class X {
>> abstract A func();
>> }
>> interface Y {
>> B func();
>> }
>> class XY: X, Y {
>> AB func() { return null; }
>> }
>> ---
>> The compiler complains about the line 'AB func() { return null; }':
>> t.d(38): function t.XY.func incompatible covariant types A() and B()
>>
>> but I think it should work, because AB is both, an A and a B, so the
>> return type is covariant with both overridden methods. In fact, the
>> example works fine, if X is an interface instead of an abstract class.
>>
>> Is this a bug or is it my mistake?
>>
>> Thanks,
>> Frank
>
> The issues is that casting from a class that implements A, B and AB to each of these results in a slightly different result.
>
> IIRC when a class is cast to an interface, what you get is a pointer to a v-table inside of the class (not the normal one). However because AB inherits from A and B, you end up getting two different v-tables. So returning an AB interface instance would give you something that is an AB and might be an A or B but not both. (This is all at the binary level of course)
So, AB isn't "A or B" but "A and B" and the OP really wants some way to say "A or B".
Specifically 'func' needs to return either A or B based on usage, eg.
A a = func(); //returns A
B b = func(); //returns B
Unfortunately you can't overload based on return type or this might have worked:
interface A {}
interface B {}
interface AB: A, B {}
abstract class X {
abstract A func();
}
interface Y {
B func();
}
template TFunc(T) { T func() { return null; } }
class XY: X, Y {
mixin TFunc!(A);
mixin TFunc!(B);
}
void main()
{
XY xy = new XY;
A a = xy.func();
B b = xy.func();
}
Regan
|
August 09, 2007 Re: Multiple inheritance and covariant return types. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Regan Heath | Regan Heath wrote:
> BCS wrote:
>> Reply to Frank,
>>
>>> Hi,
>>>
>>> I have another question on multiple inheritance. The following code
>>> does not work (tested with DMD 1.020 and 2.003)
>>>
>>> ---
>>> interface A {}
>>> interface B {}
>>>
>>> interface AB: A, B {}
>>>
>>> abstract class X {
>>> abstract A func();
>>> }
>>> interface Y {
>>> B func();
>>> }
>>> class XY: X, Y {
>>> AB func() { return null; }
>>> }
>>> ---
>>> The compiler complains about the line 'AB func() { return null; }':
>>> t.d(38): function t.XY.func incompatible covariant types A() and B()
>>>
>>> but I think it should work, because AB is both, an A and a B, so the
>>> return type is covariant with both overridden methods. In fact, the
>>> example works fine, if X is an interface instead of an abstract class.
>>>
>>> Is this a bug or is it my mistake?
>>>
>>> Thanks,
>>> Frank
>>
>> The issues is that casting from a class that implements A, B and AB to each of these results in a slightly different result.
>>
>> IIRC when a class is cast to an interface, what you get is a pointer to a v-table inside of the class (not the normal one). However because AB inherits from A and B, you end up getting two different v-tables. So returning an AB interface instance would give you something that is an AB and might be an A or B but not both. (This is all at the binary level of course)
>
> So, AB isn't "A or B" but "A and B" and the OP really wants some way to say "A or B".
>
> Specifically 'func' needs to return either A or B based on usage, eg.
>
> A a = func(); //returns A
> B b = func(); //returns B
>
> Unfortunately you can't overload based on return type or this might have worked:
>
> interface A {}
> interface B {}
>
> interface AB: A, B {}
>
> abstract class X {
> abstract A func();
> }
>
> interface Y {
> B func();
> }
>
> template TFunc(T) { T func() { return null; } }
>
> class XY: X, Y {
> mixin TFunc!(A);
> mixin TFunc!(B);
> }
>
> void main()
> {
> XY xy = new XY;
> A a = xy.func();
> B b = xy.func();
> }
Actually, ignore me I think I must have the wrong end of the stick.
Regan
|
August 09, 2007 Re: Multiple inheritance and covariant return types. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bruno Medeiros | Bruno Medeiros wrote: > Frank Fischer wrote: >> I have another question on multiple inheritance. The following code does not work (tested with DMD 1.020 and 2.003) >> >> --- >> interface A {} >> >> interface B {} >> >> interface AB: A, B {} >> >> abstract class X { >> abstract A func(); >> } >> >> interface Y { >> B func(); >> } >> >> class XY: X, Y { >> AB func() { return null; } >> } >> --- >> The compiler complains about the line 'AB func() { return null; }': >> >> t.d(38): function t.XY.func incompatible covariant types A() and B() >> > > > It's not a bug. > Classes are *convertible* to interfaces that it implements but they are > not *covariant* with said interfaces. The same thing happens for an > interface and it's super interfaces. The interface is not covariant with > is super interfaces, only convertible to them. (exception maybe the > first interface). Thus in the example above AB is not both an A and B. > This behavior is different than Java and other OO languages, and is so > for performance reasons. There are some tricks the compiler does to > allows override as if the types were covariant, but it only works in > some situations. Thanks for the explanations. So I have to live with that behaviour and handle the problem in a different way. Frank |
Copyright © 1999-2021 by the D Language Foundation