D interface bug?
Alex
sascha.orlov at gmail.com
Sat Mar 30 02:12:43 UTC 2019
On Saturday, 30 March 2019 at 00:44:31 UTC, Alex wrote:
> 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.
Maybe, CRTP is something you can use?
https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
The fact, that your interfaces are bounded to the classes in a
1:1 manner would be a hint for this...
More information about the Digitalmars-d-learn
mailing list