Mahdi Safsafi 225 Posted June 18, 2020 Hello, Take a look at the code/outputs bellow : type TMyClass = class FldEnum: (A, B, C); FldSet: set of (D, E, F); FldSubRange: 5 .. 10; FldRec: record FA: Integer; FB: Integer; end; FldInteger: Integer; FldString: string; FldArray: array [0 .. 2] of Integer; FldList: TList < (G, H, I) >; FldArrayOfRec: array [0 .. 2] of record A: Char; B: Char; end; end; type TMyClass2<T> = class(TMyClass) FldEnum: (A2, B2, C2); FldSet: set of (D2, E2, F2); FldSubRange: 5 .. 10; FldRec: record FA: Integer; FB: Integer; end; FldInteger: Integer; FldString: string; FldArray: array [0 .. 2] of Integer; FldList: TList < (G2, H2, I2) >; FldArrayOfRec: array [0 .. 2] of record A: Char; B: Char; end; end; procedure ShowRtti(AObj: TObject); var LCtx: TRttiContext; LType: TRttiType; LField: TRttiField; LFieldType: TRttiType; begin LCtx := TRttiContext.Create(); LType := LCtx.GetType(AObj.ClassInfo); Writeln('------------ RTTI for ', AObj.ToString, ' ------------'); for LField in LType.GetFields() do begin LFieldType := LField.FieldType; if Assigned(LFieldType) then begin Writeln(LField.Name:15, ' -> ', LFieldType.Name); end; end; Writeln(''); LCtx.Free(); end; var Obj1: TMyClass; Obj2: TMyClass2<Integer>; begin Obj1 := TMyClass.Create(); Obj2 := TMyClass2<Integer>.Create(); ShowRtti(Obj1); ShowRtti(Obj2); Obj1.Free(); Obj2.Free(); Readln; end. // --- outputs --- { ------------ RTTI for TMyClass ------------ FldEnum -> :TMyClass.:1 FldRec -> :TMyClass.:3 FldInteger -> Integer FldString -> string FldList -> TList<Project1.:TMyClass.:4> ------------ RTTI for TMyClass2<System.Integer> ------------ FldEnum -> TMyClass2<System.Integer>.:1 FldSet -> TMyClass2<System.Integer>.:3 FldSubRange -> TMyClass2<System.Integer>.:4 FldRec -> TMyClass2<System.Integer>.:5 FldInteger -> Integer FldString -> string FldArray -> TMyClass2<System.Integer>.:7 FldList -> TList<Project1.TMyClass2<System.Integer>.:8> FldArrayOfRec -> TMyClass2<System.Integer>.:11 FldEnum -> :TMyClass.:1 FldRec -> :TMyClass.:3 FldInteger -> Integer FldString -> string FldList -> TList<Project1.:TMyClass.:4> } As you can see, for TMyClass, some unnamed types(record, enum,) have associated RTTI. But types such (subrange, sets, array) don't have ! On the other hand, all fields of TMyClass2 have associated RTTI. This is definitely a bug as the compiler should only accept one behavior(either enables RTTI for all unnamed types or disables them). ... but the question I'm asking is : what is the correct behavior ? In other word, should an unnamed type have RTTI or not ? All typed languages I'm familiar with solved this by not allowing unnamed/anonymous types. C/C++ are an exception ! They allow both unnamed and anonymous types but they don't have RTTI system (at least an advanced system like Delphi). So its kind hard to know whats the correct behavior when there is no reference around. BTW, I'd love to see how FPC is handling it. In my opinion, I think that compiler should generate RTTI for unnamed types ... But when I think deeply I say no ! this is an unnamed type (most likely to be anonymous. You declared it implicitly ... why you should expect to have explicit RTTI in return ?) Please guys, I'm not asking for a workaround/good practice/historical reason ... just focus on the question 🙂 Share this post Link to post
Guest Posted June 19, 2020 11 hours ago, Mahdi Safsafi said: On the other hand, all fields of TMyClass2 have associated RTTI. What really does disturb me the most is FldList. Mahdi, are you familiar with DCU decompiler ? http://hmelnov.icc.ru/DCU/index.eng.html Share this post Link to post
Mahdi Safsafi 225 Posted June 19, 2020 Quote What really does disturb me the most is FldList. Wow ! I missed that ... I'll investigate and let you know. Quote Mahdi, are you familiar with DCU decompiler ? No, but sounds interesting ... I'll take a look later. Share this post Link to post
Guest Posted June 19, 2020 24 minutes ago, Mahdi Safsafi said: Quote Mahdi, are you familiar with DCU decompiler ? No, but sounds interesting ... I'll take a look later. I think it will give you faster look under the hood, i know you will like peeking under the hood 😉 , i don't mean that in perverted way, me too likey looking under the hood !! Just drag and drop the dcu on that Decompiler/Interface parser , here short of the output ( i use Notpad++ with such files, it does have Pascal coloring and save IDE from too much thinking) // parts from the output type TMyClass = class(TObject) public FldEnum: (A, B, C); FldSet: set of (D, E, F); FldSubRange: $5..$A; FldRec: record FA: Integer; FB: Integer; end; FldInteger: Integer; FldString: UnicodeString; FldArray: array[$0..$2] of Integer; FldList: {System.Generics.Collections}TList<Unit1.:TMyClass.:4>; FldArrayOfRec: array[$0..$2] of record A: Char; B: Char; end; end; {System}TArray<Unit1.:TMyClass.:4>{TArray`1<(G, H, I)>} = array of (G, H, I); //// TMyClass2`1 = class(TMyClass) public FldEnum: :TMyClass2`1.:1<T>; FldSet: set of :TMyClass2`1.:2<T>; FldSubRange: $5..$A; FldRec: :TMyClass2`1.:5<T>; FldInteger: Integer; FldString: UnicodeString; FldArray: {Unit1}TMyClass2<T>.:7; FldList: {System.Generics.Collections}TList<Unit1.TMyClass2<Unit1.TMyClass2<T>.T>.:8>; FldArrayOfRec: {Unit1}TMyClass2<T>.:11; end; //// type {Unit1}TMyClass2<T>.:7{array[$0..$2] of Integer<T>} = array[$0..$2] of Integer; {Unit1}TMyClass2<T>.:11{array[$0..$2] of (Unit1)TMyClass2<T>.:01<T>} = array[$0..$2] of {Unit1}TMyClass2<T>.:01; {Unit1}TMyClass2<T>{class(TMyClass) public FldEnum: :TMyClass2`1.:1<T>; FldSet: set of :TMyClass2`1.:2<T>; FldSubRange: $5..$A; FldRec: :TMyClass2`1.:5<T>; FldInteger: Integer; FldString: UnicodeString; FldArray: (Unit1)TMyClass2<T>.:7; FldList: (System.Generics.Collections)TList<Unit1.TMyClass2<Unit1.TMyClass2<T>.T>.:8>; FldArrayOfRec: (Unit1)TMyClass2<T>.:11; end<T>} = class(TMyClass) public FldEnum: :TMyClass2`1.:1<T>; FldSet: :TMyClass2`1.:3<T>; FldSubRange: :TMyClass2`1.:4<T>; FldRec: :TMyClass2`1.:5<T>; FldInteger: Integer; FldString: string; FldArray: {Unit1}TMyClass2<T>.:7; FldList: {System.Generics.Collections}TList<Unit1.TMyClass2<Unit1.TMyClass2<T>.T>.:8>; FldArrayOfRec: {Unit1}TMyClass2<T>.:11; end; {Unit1}TMyClass2<T>.:01{record A: Char; B: Char; end<T>} = record A: Char; B: Char; end; To @Daniel Notepad++ is handling the pascal format coloring for comments '{}' better this Insert code, you may need to look at that, i know it is very not important, but don't we all like perfection like many other things ? (e.g. peeking under the hood) Share this post Link to post
Mahdi Safsafi 225 Posted June 19, 2020 @Kas Ob. for FldList, it sounds Ok. Compiler used Integer for just the name ... all other RTTI information are valid (e.g: MaxValue). BTW, Notepad++ provides a user defined language. You can quickly make your pascal-variant 😉 Share this post Link to post
Lars Fosdal 1792 Posted June 19, 2020 Undeclared types probably do not have RTTI because it kinda pointless to be looking up an unnamed type using RTTI, since you don't have a name to look up. Besides, if you were using unnamed types in a class in production code, I'd fire you from my team. 1 Share this post Link to post
Guest Posted June 19, 2020 15 minutes ago, Lars Fosdal said: Besides, if you were using unnamed types in a class in production code, I'd fire you from my team. So, the one(s) who will allow the compiler to compile such not-OK-with-Lars should be classified as fire-proof or not fire-proof ? 😎 Share this post Link to post