Thread overview | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
October 09, 2004 Covariant returns for interfaces | ||||
---|---|---|---|---|
| ||||
I don't think this is a bug, but the inconsistency strikes me as a bit odd. Basically, covariant returns are allowed for class inheritance but not for interface inheritance. For example: # import std.stdio; # # interface I # { # I getI(); #} # # class B # { # public: # abstract B getB(); # } # # class C : I # { # public: # I getI() { return new C(); } // A # C getB() { return new C(); } # } # # # void main() # { # C c = new C(); # I i = c.getI(); # C e = c.getB(); # } This code works just fine, but if I change line A to: C getI() { return new C(); } then I get an error: "class C interface function I.getI isn't implemented." What I'm not sure of is whether this is how things *should* be. I want to say yes, but on one level it seems odd that covariant returns aren't allowed for interfaces. Sean |
October 10, 2004 Re: Covariant returns for interfaces | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | Sean Kelly wrote:
> I don't think this is a bug, but the inconsistency strikes me as a bit odd. Basically, covariant returns are allowed for class inheritance but not for interface inheritance. For example:
>
> # import std.stdio;
> #
> # interface I
> # {
> # I getI();
> #}
> #
> # class B
> # {
> # public:
> # abstract B getB();
> # }
> #
> # class C : I
> # {
> # public:
> # I getI() { return new C(); } // A
> # C getB() { return new C(); }
> # }
> #
> #
> # void main()
> # {
> # C c = new C();
> # I i = c.getI();
> # C e = c.getB();
> # }
>
> This code works just fine, but if I change line A to:
>
> C getI() { return new C(); }
>
> then I get an error: "class C interface function I.getI isn't implemented." What I'm not sure of is whether this is how things *should* be. I want to say yes, but on one level it seems odd that covariant returns aren't allowed for interfaces.
>
>
> Sean
I assume it's because the cast from C to I is non-trivial while casting from
a subclass to a superclass is trivial (ie - it doesn't generate any code).
Try the following to see what I mean:
interface A {};
class B:A {};
class C:B {};
int main() {
B b = new B;
A a = b;
printf("%p %p\n",b,a); // not the same pointer
C c = new C;
b = c;
printf("%p %p\n",b,c); // the same pointer
return 0;
}
|
October 11, 2004 Re: Covariant returns for interfaces | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ben Hinkle | Ben Hinkle wrote: > Sean Kelly wrote: > >> I don't think this is a bug, but the inconsistency strikes me as a bit odd. Basically, covariant returns are allowed for class inheritance but not for interface inheritance. For example: <snip> I do. It's been reported already, along with a related problem that probably boils down to the same thing: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D.bugs/1726 > I assume it's because the cast from C to I is non-trivial while casting from a subclass to a superclass is trivial (ie - it doesn't generate any code). Try the following to see what I mean: <snip> What would that have to do with anything? Stewart. |
October 11, 2004 Re: Covariant returns for interfaces | ||||
---|---|---|---|---|
| ||||
Posted in reply to Stewart Gordon | Stewart Gordon wrote: > Ben Hinkle wrote: >> Sean Kelly wrote: >> >>> I don't think this is a bug, but the inconsistency strikes me as a bit odd. Basically, covariant returns are allowed for class inheritance but not for interface inheritance. For example: > <snip> > > I do. > > It's been reported already, along with a related problem that probably boils down to the same thing: > > http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D.bugs/1726 > >> I assume it's because the cast from C to I is non-trivial while casting from a subclass to a superclass is trivial (ie - it doesn't generate any code). Try the following to see what I mean: > <snip> > > What would that have to do with anything? It is important when someone calls a function and expects an interface pointer returned but gets an Object pointer. The caller starts dereferencing the bogus "interface pointer" and has random behavior. To put it another way take the OP's example and suppose C.getI could be declared as returning C. Then if one executed the line I ci = cast(I)c; I i = ci.getI(); // dynamic dispatch for I.getI will not return the right pointer. By declaring the return type as I there is an implicit cast at the end of C.getI to the interface which adjusts the pointer as my example code indicated. If the return type was C that adjustment wouldn't happen since there isn't any implicit cast to I. That would mean the ci.getI() call would think it was getting the interface pointer but sometimes gets the Object pointer instead. > > Stewart. |
October 11, 2004 Re: Covariant returns for interfaces | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ben Hinkle | Ben Hinkle wrote: > Stewart Gordon wrote: > >> Ben Hinkle wrote: <snip> >>> I assume it's because the cast from C to I is non-trivial while casting from a subclass to a superclass is trivial (ie - it doesn't generate any code). Try the following to see what I mean: >> >> <snip> >> >> What would that have to do with anything? > > It is important when someone calls a function and expects an interface pointer returned but gets an Object pointer. The caller starts dereferencing the bogus "interface pointer" and has random behavior. I think we're talking a bit at cross purposes. The problem you're thinking of is that a method with an interface return type cannot be covariantly overridden with a class return type. OTOH, I was thinking of the problem that a method defined in an interface cannot be implemented with a covariant return type. The OP doesn't clarify which bug is being reported, since the example does both simultaneously. The OP's example would have equally failed if we'd defined interface I { B getB(); } instead. OTOH, your interpretation means that class B { abstract public I getI(); } class C : B { public C getI() { ... } } would fail. I'm not sure if I've tried this myself. > To put it another way take the OP's example and suppose C.getI could be declared > as returning C. Then if one executed the line I ci = cast(I)c; > I i = ci.getI(); // dynamic dispatch for I.getI > will not return the right pointer. By declaring the return type as I there > is an implicit cast at the end of C.getI to the interface which adjusts the > pointer as my example code indicated. If the return type was C that > adjustment wouldn't happen since there isn't any implicit cast to I. <snip> You have a point. I can now guess that an interface pointer is a combination of an object pointer and a pointer to the interface's vtbl. I wonder if they can be implemented differently such that this problem doesn't exist.... Stewart. |
October 11, 2004 Re: Covariant returns for interfaces | ||||
---|---|---|---|---|
| ||||
Posted in reply to Stewart Gordon | "Stewart Gordon" <smjg_1998@yahoo.com> wrote in message news:cke6id$1hkp$1@digitaldaemon.com... > Ben Hinkle wrote: > > Stewart Gordon wrote: > > > >> Ben Hinkle wrote: > <snip> > >>> I assume it's because the cast from C to I is non-trivial while casting from a subclass to a superclass is trivial (ie - it doesn't generate any code). Try the following to see what I mean: > >> > >> <snip> > >> > >> What would that have to do with anything? > > > > It is important when someone calls a function and expects an interface pointer returned but gets an Object pointer. The caller starts dereferencing the bogus "interface pointer" and has random behavior. > > I think we're talking a bit at cross purposes. > > The problem you're thinking of is that a method with an interface return type cannot be covariantly overridden with a class return type. > > OTOH, I was thinking of the problem that a method defined in an interface cannot be implemented with a covariant return type. > > The OP doesn't clarify which bug is being reported, since the example does both simultaneously. > > The OP's example would have equally failed if we'd defined > > interface I { > B getB(); > } > > instead. OTOH, your interpretation means that > > class B { > abstract public I getI(); > } > > class C : B { > public C getI() { ... } > } > > would fail. I'm not sure if I've tried this myself. I see what you mean. It does seem wierd that an interface can't be implemented covariantly. I don't know if there is a technical reason for this. > > To put it another way take the OP's example and suppose C.getI could be declared > > as returning C. Then if one executed the line > > I ci = cast(I)c; > > I i = ci.getI(); // dynamic dispatch for I.getI > > will not return the right pointer. By declaring the return type as I there > > is an implicit cast at the end of C.getI to the interface which adjusts the > > pointer as my example code indicated. If the return type was C that adjustment wouldn't happen since there isn't any implicit cast to I. > <snip> > > You have a point. I can now guess that an interface pointer is a > combination of an object pointer and a pointer to the interface's vtbl. > I wonder if they can be implemented differently such that this problem > doesn't exist.... I was thinking about that, too. I'm not a compiler writer so I don't know exactly how interfaces are implemented but there are probably a few possibilities. It would be nice to have objects and interfaces share the same pointer. It's probably not easy, though. > > Stewart. |
October 11, 2004 Re: Covariant returns for interfaces | ||||
---|---|---|---|---|
| ||||
Posted in reply to Stewart Gordon | In article <cke6id$1hkp$1@digitaldaemon.com>, Stewart Gordon says... > >The problem you're thinking of is that a method with an interface return type cannot be covariantly overridden with a class return type. > >OTOH, I was thinking of the problem that a method defined in an interface cannot be implemented with a covariant return type. > >The OP doesn't clarify which bug is being reported, since the example does both simultaneously. I was reporting the latter problem. Sorry for the confusion. Sean |
October 11, 2004 Re: Covariant returns for interfaces | ||||
---|---|---|---|---|
| ||||
Posted in reply to Stewart Gordon | In article <cke6id$1hkp$1@digitaldaemon.com>, Stewart Gordon says... > >You have a point. I can now guess that an interface pointer is a combination of an object pointer and a pointer to the interface's vtbl. > I wonder if they can be implemented differently such that this problem >doesn't exist.... Yup. I'd forgotten about this. If that's the way it has to be then that's fine, but it would be nice if it didn't... Sean |
October 11, 2004 Re: Covariant returns for interfaces | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | In article <ckea98$1l8o$1@digitaldaemon.com>, Sean Kelly says... > >In article <cke6id$1hkp$1@digitaldaemon.com>, Stewart Gordon says... >> >>The problem you're thinking of is that a method with an interface return type cannot be covariantly overridden with a class return type. >> >>OTOH, I was thinking of the problem that a method defined in an interface cannot be implemented with a covariant return type. >> >>The OP doesn't clarify which bug is being reported, since the example does both simultaneously. > >I was reporting the latter problem. Sorry for the confusion. BTW, here's a test case that avoids the other issue: # class B # { # public: # abstract B getB(); # } # # class C : B # { # public: # override C getB() { return new C(); } # } # # interface I # { # B getI(); # } # # # class D : I # { # public: # C getI() { return new C(); } # } # # # void main() # { # # } Error is: "test.d(20): class D interface function I.getI isn't implemented" Now in a sense I can understand the logic behind this--interfaces are kind of like a contract imposed on an implementation. But I still find it a bit odd that covariant returns works for inheritance from abstract base classes but not from interfaces. Not a big issue, but I figured it was worth mentioning. Sean |
Copyright © 1999-2021 by the D Language Foundation