[fpc-pascal] class inheritance and type incompatibility
Sven Barth
pascaldragon at googlemail.com
Sun Sep 29 11:05:11 CEST 2013
On 29.09.2013 04:47, Xiangrong Fang wrote:
> 2013/9/29 Sven Barth <pascaldragon at googlemail.com
> <mailto:pascaldragon at googlemail.com>>
>
>
> If you want to override the virtual Clone method of TTree<LongInt>
> in TIntTree you need to use the same result type + override or
> otherwise you gain nothing, because the compiler will not consider
> the method as overloaded and use the Clone method of TTree<LongInt>
> inside TTree<LongInt>'s methods instead.
>
>
> Yes, you are right, for virtual method, you need have exactly same
> type... But this leads me to think how the generics are implemented?
The important things about generics:
- The generic type itself (in this case TTree<>) does *not* exist inside
the code (bugs not withstanding...), only the textual representation of
the generic exists as metadata inside the PPU (which you can not access
from a program)
- When specializing a generic the compiler loads this metadata and
reparses the textual representation whereby the generic type parameters
are replaced by the types you specified, so in code a "specialize
TTree<Integer>" looks like a "TTree<T>" which you manually have made
non-generic and replaced each occurence of "T" with "Integer".
> For
> example:
>
> === snippet 1 ===
> type
> TIntTree = class(specialize TTree<Integer>)
> public
> function Clone: TTree; override;
> end;
> === end of snippet 1 ===
>
> This will leads to a compile error: Generics without specialization
> cannot be used as a type for a variable.
"TTree" is not valid anywhere except inside the declaration of the
generic (and only in non-Delphi modes).
>
> If so, why in the code TTree can be used everywhere, for example:
>
> === snippet 2 ===
> function TTree.Level: Cardinal;
> var
> n: TTree; <-- here TTree is not specialized.
> begin
> ... ...
> end;
> === end of snippet 2 ===
>
> In snippet 1, why the compiler don't treat the TTree same as its own
> type i.e. TIntTree? I imagine that TTree in snippet 1 is logically
> similar to TObject. I mean, a class's method is of course possible to
> return a value of its parent's type or any other class's instance?
In case of generics in non-Delphi modes the own class name without
generic parameters (here "TTree") is a place holder for the own type of
the generic. The compiler replaces any reference to this type with
references to the generic you are declaring. If you now specialize a
generic (e.g. "specialize TTree<LongInt>") all those references are now
handled as references to "TTree<LongInt>".
>
> Would you please show how exactly you changed the code? With all
> those methods calling each other it's a bit hard to imagine in my
> head what you changed. ;)
>
>
> With your TSelfClass solution in TTree, I mean either:
>
> === solution 1 ===
> type
> TIntTree = class(specialize TTree<Integer>
> public
> function Clone: TIntTree;
> end;
> function TIntTree.Clone: TIntTree;
> begin
> Result := TIntTree(inherited Clone); //typecast in TIntTree
> end;
> === end of solution 1===
> or:
> === solution 2 ===
> type
> TIntTree = class(specialize TTree<Integer>)
> end;
> begin //main
> it2 := TIntTree(it1.Clone); //typecast in main program
> end.
> === end of solution 2 ===
>
> Are both solutions correct?
Yes, correct are both.
Regards,
Sven
More information about the fpc-pascal
mailing list