On Saturday, 30 March 2019 at 00:06:23 UTC, H. S. Teoh wrote:
On Fri, Mar 29, 2019 at 11:44:35PM +0000, Alex via
Digitalmars-d-learn wrote:
interface iBase
{
iBase fooBase(iBase);
}
class cBase : iBase
{
cBase fooBase(cBase c) { return c; }
}
cBase.fooBase should be a valid override of iBase.fooBase
because they are the same type! cBase is a super type so it
contains everything iBase contains and maybe more.
No, that's wrong. Consider this:
class cBase : iBase
{
int x;
cBase fooBase(cBase c) { return (x==1) ? c : null; }
}
class dBase : iBase
{
string y;
dBase fooBase(dBase c) { return (y=="a") ? c : null; }
}
iBase intf = new cBase;
dBase dobj = new dBase;
dobj.fooBase(intf); // oops: intf.y doesn't exist!
I.e., it's invalid for dBase.fooBase to override the interface
method.
The parameter type of fooBase must be the interface type or a
super-interface thereof. For a class C to inherit from an
interface X means that C contains a subset of all possible
objects that X might refer to. Therefore, if a method takes a
parameter of type C, it *cannot* be passed an argument of type
X, since the actual object might be outside the subset that C
includes. IOW, such a method cannot be covariant with a method
that takes X as a parameter.
There should be no reason why the compiler can't figure this
out. It's a very simple rule.
Any time the user calls iBase.fooBase it can be replaced with
cBase.fooBase so it should not compromise any code to go ahead
and accept it as a proper override.
[...]
Nope. The user can call iBase.fooBase, passing it an instance
of a different class that also implements iBase but does not
inherit from cBase. Then cBase.fooBase would receive an
argument of incompatible type.
T
Ok. In my use case, which is what I was thinking of, there will
never be a dBase. There will never be any other class that
inherits from the interface. I have to use an interface ONLY
because D does not allow for multiple inheritance.
class X;
class C;
class Q : X, C;
Which can't be done, so I want to do
interface iC;
class C : iC;
class Q : X, iC;
which now works. The problem now is that I have to then still
follow these rules which are very restrictive. It's true that
someone could come along and create an new class D : iC and cause
problems, but that should never happen in my case. Ideally, if
they did, they would use the same pattern as above:
interface iD;
class D : C, iD;
and this then also alleviates the problem.
In your case it is
iC
/ \
/ \
C D
but in my case it should never happen, or if it would, it is
better to do
iC
/
/
C iD
\ /
\ /
D
I'm only using interfaces because I have to, not because I want
to. But then that forces me to do strange things in D and it
causes many problems. Since one can't have fields in an interface
it requires using properties and all that code bloat that comes
with them, along with the casting issues, and overloading, etc.