0
type
  TTestHelper = class helper for TStringList
    procedure Test;
  end;

What is the actual implementation of Delphi class helpers? In the System unit, I can find the define of TClassHelperBase. According to FreePascal's documentation, it says its Delphi mode implements it as a base class for both class and record helpers. But I cannot find anything useful in Embarcadero's documentation.

TClassHelperBase = class(TInterfacedObject, IInterface)
  protected
    FInstance: TObject;
    constructor _Create(Instance: TObject);
  end;

The base class is not even compiled in Delphi. So I'm a bit confused.

I have tested that I could call the helper methods with TMethod. Why is that?

6
  • The details of how class/record helpers are implemented is not publicly documented by Embarcadero. Commented Aug 12 at 15:10
  • @RemyLebeau I'm aware of that. But how TObject is implemented has a lot of resources to read. I have difficulties to find helper related infos. Commented Aug 12 at 15:23
  • The question is why you would need such information at all!? Commented Aug 13 at 9:46
  • 2
    @DelphiCoder why not? Curiosity isn't a crime (yet). Commented Aug 13 at 11:50
  • @dummzeuch Indeed! ;-) Commented Aug 13 at 15:32

1 Answer 1

2

I think this is best explained with some code:

uses
  System.SysUtils,
  System.Rtti;

type
  TFoo = class
    procedure X;
  end;

  TFooHelper = class helper for TFoo
    procedure Y;
  end;

procedure TFoo.X;
begin
  Writeln('TFoo.X');
end;

procedure TFooHelper.Y;
begin
  Writeln('TFooHelper.Y');
end;

var
  f: TFoo;
  ctx: TRttiContext;
  t: TRttiType;
  m: TRttiMethod;
  i: TRttiInterfaceType;
begin
  f := TFoo.Create;
  f.X;
  f.Y;
  // Looking at the assembly code for these two calls will show this 
  // (remember to turn off ASLR if you have a recent Delphi version as that
  // disables the possibility to see the method names):
  //   call TFoo.X
  //   call TFooHelper.Y

  Writeln('Methods of TFoo:');
  t := ctx.GetType(TFoo);
  for m in t.GetMethods do
    Writeln('  ', m.ToString);
  // Okay, we don't see that method there, what if...

  Writeln;
  Writeln('Methods of TFooHelper:');
  t := ctx.GetType(TypeInfo(TFooHelper));
  for m in t.GetMethods do
    Writeln('  ', m.ToString);
  // Ah! And it looks like it was inherited from TObject, or? Let's see...

  Writeln;
  while True do
  begin
    t := t.BaseType;
    if t = nil then Break;
    Writeln(t.ToString);
  end;
  // Oh, there is that TClassHelperBase, and it inherits from TInterfacedObject - I wonder if...

  Writeln;
  t := ctx.GetType(TypeInfo(TFooHelper));
  if t is TRttiInstanceType then
  for i in TRttiInstanceType(t).GetDeclaredImplementedInterfaces do
    Writeln(i.ToString);
  // No, it does not implement any other interfaces.

  Readln;
end.

Things get a bit more interesting when you implement virtual methods on the helper because then the compiler puts some interface onto that generated class which you cannot easily get via the GetDeclaredImplementedInterfaces because their TypeInfo is nil. But stepping through the call of a virtual method call will show how it works internally.

Sign up to request clarification or add additional context in comments.

1 Comment

It would be useful if you include the output of your WriteLn's in your post, summarize what the output is showing, and explain how this actually answers the OP's question of how helpers are implemented.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.