Any way to override base type with dervived in derived type

IntegratedDimensions IntegratedDimensions at gmail.com
Fri May 25 00:15:39 UTC 2018


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.




More information about the Digitalmars-d-learn mailing list