RTTI errors and omissions in Delphi XE

I’ve been playing around with DeHL a lot lately.  Embarcadero’s own Alex Ciobanu wrote this library, which provides a lot of useful functionality, including a set of querying methods that, while a bit bulky, are probably the best we’re gonna get until the compiler team gets around to implementing LINQ as a language feature.  (Which I really hope they will do.)

It uses a lot of generic interfaced collections to pull this off without making a huge mess of the memory management.  This is particularly interesting because during the keynote at Delphi Live, someone (I think it was Mike Rozlog, but I’m not certain–where are the videos I saw some people taking?) said that they’re working on a more modern VCL.  I asked what they meant by that, and one of the answers was more interfaces in more places.

Between that and a lot of other things they’ve done recently, it seems like they want to bring the VCL to parity with the .NET framework.  But we’ve got a lot of problems with the interfaces, especially when you bring RTTI into it.  For example, a bit of fun I discovered yesterday.  What would you expect this program to output?

program Project3;

{$APPTYPE CONSOLE}

uses
  SysUtils, RTTI,
  dehl.Collections.base;

type
   IntList = IList<integer>;

   TMyObject = class
   private
      FName: string;
      FNumbers: IntList;
   end;

procedure Test;
const
   FIELD_STRING = 'Field: %s, Type: %s';
var
   ctx: TRttiContext;
   field: TRttiField;
begin
   ctx := TRttiContext.Create;
   for field in ctx.GetType(TMyObject).GetFields do
      writeln(format(FIELD_STRING, [field.Name, field.FieldType.Name]));
end;

begin
  try
    { TODO -oUser -cConsole Main : Insert code here }
    test;
    readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

You’d expect to see:

Field: FName, Type: string
Field: FNumbers, Type: IntList

Or maybe, IList<integer> as the type for FNumbers.  But do you know what you do get?  On both D2010 and Delphi XE, you get an access violation, since the compiler doesn’t generate RTTI for generic interfaces, so field.FieldType returns nil.

I had really hoped that that would be fixed in XE.  It’s disappointing to see that it hasn’t been.  The compiler needs to be able to generate RTTI for every valid type and member in the language.  (For even more fun, try using RTTI to discover information on the members of an interface, even simple ones like IInterface.  Go ahead, see what you come up with.)  We need full RTTI support for all generics, for indexed properties, and for odd types such as sets larger than 32 bits or non-contiguous enumerations.  Without this, it just feels like a crippled feature that’s just waiting to trip over something and throw an access violation in code that ought to work.

11 Comments

  1. Stefan says:

    Some workaround for this special case would be:

    IntList = interface(IList<Integer>>)
    end;

  2. Please QC this 😉
    –jeroen

  3. Chris says:

    Excellent post. The response of ‘well I/we had to stop somewhere’ (which is what came out with D2010) is acceptable for a first release but increasingly dubious thereafter.

  4. Mason Wheeler says:

    @Stefan: Yeah, that works for this specific example, but it only pushes the real issue back a step. What happens when you try to use the interface type’s BaseType property?

    @Chris: I agree completely.

  5. Ali says:

    Hi Mason; sorry this comment is not directly related to your post; it seems your hosting company is blocking access to your weblog from certain countries (I can confirm it for Iran). I am not sure if you are aware of this restriction or not, so I thought I should let you know about it.

    BTW, thanks for your nice post.

    Regards

  6. Barry Kelly says:

    I understand folks being upset over the lack of complete coverage in RTTI. There wasn’t any increase in coverage for XE because other work had priority (64-bit, x-plat, a front end that could support LINQ, more things that I can’t talk about). There’s no end of things we could be doing, and there’s always someone looking for more in every area, not to mention people upset by the executable space consumption. I’ll try to find time to improve RTTI coverage specifically going forward, but naturally that means less time spent elsewhere.

  7. Zlatibor Boro Urosevic says:

    @Barry: ” I’ll try to find time to improve RTTI coverage specifically going forward, but naturally that means less time spent elsewhere.”

    I suppose working on RTTI is a complex stuff covered by a bigger team and not a single person…at least hoping so… ;o)

  8. Mason Wheeler says:

    @Ali: Thanks for bringing this to my attention. I’ll see what I can do.

    @Barry: Good point. I can’t speak for everyone, but personally, I’d prefer to see old, half-finished features finished before starting on new ones. Especially really useful features like extended RTTI.

  9. eric says:

    +1 on finishing features like Mason said.
    An incomplete half-working Rtti is indeed just a waste of executable size…

  10. […] Downloads « RTTI errors and omissions in Delphi XE […]

  11. zarandok says:

    Hello!

    Have you ever seen this XE specific error:

    [DCC Error] Unit1.pas(18): E2575 RTTI for ‘tMyTestEnum’ is too large; reduce scope with $RTTI or reduce type size

    for enums containing more then 2 680 values (however this number depends on total length of enum declaration, my one is slightly less then 70 885 bytes).

    This is 100% reproducible and happens only in Delphi XE, not in older versions like D2007 and 2010.

    Things like
    {$WEAKLINKRTTI ON}
    {$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}
    doesn’t help at all.

    Any suggestion is welcomed and greatly appreciated.