Community pulse: CodeRage 4, RTTI Reloaded

Narcissistic EagleCodeRage 4 is very close so the Embarcadero guys started to promote it – seeing it’s schedule I think that it will be a very nice virtual conference with the main focus (of course) on RAD Studio 2010. DavidI wrote a nice post summing up everything that you’ll need to know if you’re interested.

But on the ‘dark side of the moon’, there is enough interest in the new RTTI engine. Let us summarize some quick facts in order to clear up some misunderstandings: (Barry please CIIW 🙂 )…

  • TRTTIContext is a record which holds an interface inside, hence it is created at its first use and disposed when it goes out of scope. So no need to call the .Create and/or .Free. Under the hood it manages a Pool of RTTI objects in order to allow you to easily work with all your RTTI objects without being forced to manage the lifetime of these objects. Very handy. You can see TRTTIContext  as a cache if you want.
  • The records have in D2010 RTTI info by default.
  • The size of the exe file will increase due of new RTTI info. The grow percentage usually isn’t significant, but for the developers which are very sensible to their application size there are some tools to reduce the code size: {$WEAKLINKRTTI ON} and {$RTTI EXPLICIT METHODS([]) FIELDS([]) PROPERTIES([])} – we must note that the latter compiler directive disables the new RTTI only for the types (classes, records etc.) declared in the unit where you put it, so including it only once at the top of one unit is not enough. You need to add it to the top of every unit that declare types in addition to {$WEAKLINKRTTI ON}. Of course, if you want to strip out this info from VCL you must recompile it.
  • With the new RTTI you will gain access also at  Private members. To illustrate this, and also the above one, here’s a snippet from System.pas:

{ RTTI Visibility }
type
  TVisibilityClasses = set of (vcPrivate, vcProtected, vcPublic, vcPublished);

const
  { These constants represent the default settings built into the compiler.
    For classes, these settings are normally inherited from TObject. }
  DefaultMethodRttiVisibility = [vcPublic, vcPublished];
  DefaultFieldRttiVisibility = [vcPrivate..vcPublished];
  DefaultPropertyRttiVisibility = [vcPublic, vcPublished];

type
  { Default RTTI settings }
  {$RTTI INHERIT
      METHODS(DefaultMethodRttiVisibility)
      FIELDS(DefaultFieldRttiVisibility)
      PROPERTIES(DefaultPropertyRttiVisibility)} 

  { Minimal RTTI generation henceforth in this file }
  {.$RTTI EXPLICIT METHODS([]) FIELDS([]) PROPERTIES([])} 

  TArray<T> = array of T; //this is not related to RTTI of course 😉

Also, I included in the last line a new definition from System.Pas: a generic array. Believe me, this is much more useful than it sounds. No more hundredths of definitions like TDynamicIntegerArray, TStringDynamicMatrix etc. etc. etc.

  • As, perhaps, you could imagine, the exe size grow is mainly due of methods body which can be invoked dynamically at runtime even if they aren’t used explicitly in code. You have now the possibility to invoke any method at runtime. See the definition from RTTI.pas:
 TRttiType = class(TRttiNamedObject)
  //snipped
 public
    function GetMethods: TArray<TRttiMethod>; overload; virtual;
    function GetFields: TArray<TRttiField>; virtual;
    function GetProperties: TArray<TRttiProperty>; virtual;

    function GetMethod(const AName: string): TRttiMethod; virtual;
    function GetMethods(const AName: string): TArray<TRttiMethod>; overload; virtual;
    function GetField(const AName: string): TRttiField; virtual;
    function GetProperty(const AName: string): TRttiProperty; virtual;

    function GetDeclaredMethods: TArray<TRttiMethod>; virtual;
    function GetDeclaredProperties: TArray<TRttiProperty>; virtual;
    function GetDeclaredFields: TArray<TRttiField>; virtual;
 end;

Where TRttiMethod is a very nice class, hosting of course some ‘interesting’ declarations like:

  TRttiMethod = class(TRttiMember)
 //snip
  public //of course the methods bellow will ACTUALLY EXECUTE the method
    function Invoke(Instance: TObject; const Args: array of TValue): TValue; overload;
    function Invoke(Instance: TClass; const Args: array of TValue): TValue; overload;
    function Invoke(Instance: TValue; const Args: array of TValue): TValue; overload;
    function GetParameters: TArray<TRttiParameter>; virtual; abstract;
    function ToString: string; override;
    property ReturnType: TRttiType read GetReturnType;
  end;
  • Few words about TValue. Even if isn’t entirely true, you can see TValue like a variant on steroids, safer and better adapted to Delphi’s type system. Just one hint in order to prevent frustrations: due of safety considerations silent conversions are “discouraged” – AsType / Cast methods are only for what would normally be implicit conversions in Delphi. Look here and read the comments:
var
  foo: TValue;

begin
  foo:=42; //an integer
  ShowMessage(foo.AsString); //this will throw an exception. In Delphi Integer -> String isn't allowed
  ShowMessage(foo.ToString);
  {the above will work - we have for our convenience .ToString
  in order to convert almost 'everything' to a string}
end;

Of course you have testing functions like TValue.IsType: boolean; as well as function TValue.TryAsType(out AResult: T): Boolean;

Hoping that the above will answer some of your questions, I expect your feedback on the above things.

PS: Thanks to Barry Kelly for some insights on the above, and first of all for the implementation, no?

4 thoughts on “Community pulse: CodeRage 4, RTTI Reloaded

  1. Hello,

    The new RTTI looks AWESOME!!!!

    Is there a performance penatly to using a new TRttiContext in every method (where it will go in and out of scope) vs wrapping it in a singleton for the whole app? Since the RTTI does not change in the lifetime of the app, is there any reason not to use a singleton? Is thread-safety and issue?

    • The intended usage case usually is having a small number of TRTTIContext instances (IOW if you can have a singleton, that’s fine – but it varies from situation to situation) and keep it alive as long as possible – this will give the opportunity to have already ‘cached’ as many RTTI objects as possible, hence the query speed will be normally faster. But if you have very tight memory constraints and/or you’ll have in TRTTIContext’s object pool many objects which are just taking space (IOW you ‘know’ that you will not (re)query for them) perhaps is better to have several instances of TRTTIContexts.

      Also, while I cannot test it right now (I have some problems with my installation) there is a locking protocol on the pool of objects inside of TRTTIContext. So, most probably is thread-safe.

    • Yes. In the same manner – through the Properties property. Is the responsibility of the class’s writer to hide this info. All the RTTI info is visible by default. Perhaps is better to know that Properties return an TArray where TRttiProperty is inherited from TRttiMember which has a Visibility: TMemberVisibility; property.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s