Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2015-10

RTTI and generics: accessing specialized class instance

5 messages · 2 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

leledumbo

Consider the following:

type
  generic TGenClass<T> = class
  ...
  end;
  TSpecType = specialize TGenClass<Integer>;
  TMyClass = class
    FST: TSpecType;
    procedure p;
  published
    ST: TSpecType read FST write FST;
  end;
procedure TMyClass.p;
...
begin
  PropCount := GetPropList(Self,Props);
  for i := 0 to PropCount - 1 do begin
    Prop := Props^[i];
    PropName := Prop^.Name;
    case Prop^.PropType^.Kind of
      tkObject: begin
        Obj := GetObjectProp(Self,Prop); //1
        ...
      end;
    end;
  end;
end;

In //1, GetObjectProp will return TObject for ST property. Since generic types without specialization cannot be used in type declaration, how can I get the actual type of ST and cast Obj to it so I can access its properties? Note that ST here is just an example, there could be multiple TGenClass specialization that TMyClass uses.

View this message in context: http://free-pascal-general.1045716.n5.nabble.com/RTTI-and-generics-accessing-specialized-class-instance-tp5723011.html Sent from the Free Pascal - General mailing list .

Reply by email

Sven Barth
to leledumbo
leledumbo wrote 37 lines
Consider the following: type generic TGenClass<T> = class ... end; TSpecType = specialize TGenClass<Integer>; TMyClass = class FST: TSpecType; procedure p; published ST: TSpecType read FST write FST; end; procedure TMyClass.p; ... begin PropCount := GetPropList(Self,Props); for i := 0 to PropCount - 1 do begin Prop := Props^[i]; PropName := Prop^.Name; case Prop^.PropType^.Kind of tkObject: begin Obj := GetObjectProp(Self,Prop); //1 ... end; end; end; end; In //1, GetObjectProp will return TObject for ST property. Since generic types without specialization cannot be used in type declaration, how can I get the actual type of ST and cast Obj to it so I can access its properties? Note that ST here is just an example, there could be multiple TGenClass specialization that TMyClass uses.

TGenClass is not a full type, only TGenClass<Integer> is, so you need to use - in your example - TSpecType(Obj). In Delphi mode you could also use TGenClass<Integer>(Obj). For mode ObjFPC you'll need to wait till I've finished generic functions, cause then "specialize TGenClass<Integer>(Obj)" will work as well.
Note: specializations can also be declared locally in a procedure/function/method in a type section.

Regards,
Sven

Reply by email

leledumbo
to Sven Barth
TGenClass is not a full type, only TGenClass<Integer> is, so you need to

use - in your example - TSpecType(Obj)

Yes, I'm aware of this. The problem is I don't know TSpecType which I said the last note. It could be any user defined specialization of TGenClass. Back to above code, but closer to my actual complex code:

// my library
type
  TMyClass = class
    procedure mp;
  end;
  generic TGenClass<T> = class
    procedure gp;
  end;
procedure TMyClass.mp;
begin
  PropCount := GetPropList(Self,Props);
  for i := 0 to PropCount - 1 do begin
    Prop := Props^[i];
    PropName := Prop^.Name;
    case Prop^.PropType^.Kind of
      tkObject: begin
        Obj := GetObjectProp(Self,Prop); // this is where I may get
specialized TGenClass instance
        ...                                              // and I need to
call its gp method
      end;
    end;
  end;
end;
procedure TGenClass.gp;
begin
  ...
end;
// user of my library
type
  THisType = specialize TGenClass<TWhateverHeChoose>;

THisClass = class(TMyClass)
...

  published
    ...
    HT: THisType read FHT write FHT; // this is what TMyClass.mp will get

above, which it doesn't know about

                                                      // because it's

declared later, much much later

  end;

I hope you can get the better picture. One solution is not to use generics and return to good old inheritance, but I'm still thinking if there's a solution without sacrificing the generics. I don't know how other languages which has generics/templates solve this problem, though. Might be worth a research.

Reply by email

Sven Barth
to leledumbo
"leledumbo" wrote
> TGenClass is not a full type, only TGenClass<Integer> is, so you need

to

Show quoted text 6 lines
use - in your example - TSpecType(Obj) Yes, I'm aware of this. The problem is I don't know TSpecType which I said the last note. It could be any user defined specialization of TGenClass. Back to above code, but closer to my actual complex code:

[snip]

I hope you can get the better picture. One solution is not to use generics and return to good old inheritance, but I'm still thinking if there's a solution without sacrificing the generics. I don't know how other

languages

which has generics/templates solve this problem, though. Might be worth a research.

You'll have the problem to know the specific class at compile time no matter whether you use generics or inheritance. If you want access to specific methods of the published then I suggest you to either have that class implement an interface or to have it inherit from a common base class that you can check for using "is" (yes, a generic can inherit from a normal class without problems).

Regards,
Sven

Reply by email

leledumbo
to Sven Barth
You'll have the problem to know the specific class at compile time no

matter whether you use generics or inheritance

Not really, with inheritance, I can just cast the TObject returned by GetObjectProp to the parent class (TGenClass). Because that's all I need: accessing TGenClass members.

If you want access to specific methods of the published then I suggest you to either have that class implement an interface or to have it inherit from a common base class that you can check for using "is" (yes, a generic can inherit from a normal class without problems).

Aha! That's right, I can implement the methods/fields/whatever in a normal class which is then extended by the generic class. This is a hybrid generics-inheritance approach, should've thought about it. Thanks for the enlightenment.

Reply by email