Any way to override base type with dervived in derived type

Basile B. b2.temp at gmx.com
Fri May 25 01:02:00 UTC 2018


On Friday, 25 May 2018 at 00:15:39 UTC, IntegratedDimensions 
wrote:
> On Thursday, 24 May 2018 at 23:31:50 UTC, Alex wrote:
>> On Thursday, 24 May 2018 at 20:24:32 UTC, IntegratedDimensions 
>> wrote:
>>> class T;
>>> class TT : T;
>>>
>>> interface I
>>> {
>>>    @property T t();
>>> }
>>>
>>> abstract class A
>>> {
>>>    T _t;
>>>    @property T t() { return _t; }
>>>
>>> }
>>>
>>> class C : A
>>> {
>>>
>>>    // Stuff below uses t as TT but compiler, of course, 
>>> treats t as T
>>>    ...
>>> }
>>>
>>>
>>> The issue is that I programmed the class C with a variable 
>>> that directly was based off TT, I later subderived T from TT 
>>> and exposed it in I. (TT was refactored in to T and not T)
>>>
>>
>> As as a side note:
>> I can hardly follow this, as you don't show, where you use the 
>> interface I. However, especially if TT was refactored in such 
>> a way, that is a set difference of T and not T, why you choose 
>> to derive from T instead of to contain T?
>>
>
> It really should be obvious that A was meant to derive from I. 
> This is just standard oop.  Simply leaving off : I should not 
> be a deal breaker because it would not change the whole problem 
> from black to white or vice versa.
>
> T is a member to be included. You can only derive from one 
> class. C can't derive from both A and T and even if it did, it 
> would mean something else.
>
>
>
>> https://en.wikipedia.org/wiki/Composition_over_inheritance
>> http://wiki.c2.com/?CompositionInsteadOfInheritance
>>
>> Well, can imagine useful cases though...
>>
>
> This is not a composition pattern.
>
> This is a parallel inherentence pattern.
>
> TT : T = T
> |    |   |
> v    v   v
> C  : A : I
>
> TT is used with C and T with I.
>
> When C changes to C', TT : T changes to TT' : T
>
> All functions that use TT in C are forced to use it as if it 
> were of type T rather than TT which requires a bunch of casts.
>
> This is generally a violation of type logic. There is nothing 
> in that prevents t from being something like TTT which has no 
> direct relation to TT.
>
> But the programming logic of the code enforces t to be of type 
> TT in C *always*. So I don't know why I would have to use 
> casting all the time. It would be nice if there where a simple 
> logical way to enforce a design pattern in the type system 
> knowing that it is enforced at runtime. This makes cleaner 
> code, nothing else.
>
>
>
>>>
>>> But all the code in C assumes t is of type TT but now due to 
>>> the interface it looks like a T, even though internally it is 
>>> actually a TT.
>>>
>>> What I'd like to do is
>>>
>>> class C : A
>>> {
>>>    private override @property TT t() { return cast(TT)(_t); } 
>>> // null check if necessary
>>>    // Stuff below uses t which is now a TT
>>>    ...
>>> }
>>>
>>> or whatever.
>>>
>>> This is simply so I don't have to rename or cast all my uses 
>>> of t in C to type TT.
>>>
>>> I'm pretty much guaranteed that in C, t will be type TT due 
>>> to the design(C goes with TT like bread with butter).
>>>
>>> So, it would be nice if somehow I could inform the type 
>>> system that in C, t is always of type TT and so treat it as 
>>> such rather than forcing me to explicitly cast for every use. 
>>> Again, I could rename things to avoid the same name usage but 
>>> in this case it is not necessary because of the design.
>>>
>>> Is there any semantics that can get me around having to 
>>> rename?
>>
>> Maybe, you are looking for Curiously Recurring Template 
>> Pattern?
>>
>> ´´´
>> interface I(P)
>> {
>> 	@property P t();
>> }
>>
>> abstract class T(P) : I!P
>> {
>>     P _p;
>>     @property P t() { return _p; }
>> }
>>
>> class TT : T!TT
>> {
>>
>> }
>>
>> void main()
>> {
>> 	auto tt = new TT();
>> 	static assert(is(typeof(tt.t) == TT));
>> }
>> ´´´
>
> No, I am trying to keep parallel derived types consistently 
> connected. If A is derived from B and C from D and B uses D 
> then A uses C. Consistency cannot be guaranteed by the type 
> system at compile time because A is typed to use C, I want to 
> restrict it further to D.

You must put a template parameter in the interface and specialize 
the class that implements the interface.

```
module runnable;

class T{}
class TT : T{}

interface I(N)
{
    @property N t();
}

abstract class A(N) : I!N
{
    N _t;
    @property N t() { return _t; }
}

class C1 : A!T{}
class C2 : A!TT{}

void main(string[] args)
{
     import std.traits;
     static assert(is(ReturnType!(C1.t) == T));
     static assert(is(ReturnType!(C2.t) == TT));
}

module runnable;

class T{}
class TT : T{}

interface I(N)
{
    @property N t();
}

abstract class A(N) : I!N
{
    N _t;
    @property N t() { return _t; }
}

class C1 : A!T{}
class C2 : A!TT{}

void main(string[] args)
{
     import std.traits;
     static assert(is(ReturnType!(C1.t) == T));
     static assert(is(ReturnType!(C2.t) == TT));
}
```

but obviously this won't work if you want to derive C1 or C2...


More information about the Digitalmars-d-learn mailing list