On 29.09.2013 04:47, Xiangrong Fang wrote:
2013/9/29 Sven Barth <pascaldra...@googlemail.com
<mailto:pascaldra...@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

_______________________________________________
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
http://lists.freepascal.org/mailman/listinfo/fpc-pascal

Reply via email to