Steffen Binas
Steffen Binas

Reputation: 1468

Delphi Web Script: How to Expose a Class via RTTI which contains a Method returning another (exposed) Class

I have this Delphi class

type
  TAnotherClass = class
  end;

  TMyClass = class
    function Foo: TAnotherClass;
  end;

function TMyClass.Foo: TAnotherClass;
begin
  Result := TAnotherClass.Create;
end;

Now I'd like to expose this class via "dwsRTTIExposer.pas":

myUnit.ExposeRTTI(TypeInfo(TMyClass));
myUnit.ExposeRTTI(TypeInfo(TAnotherClass));

My Script looks like that:

var a: TMyClass = TMyClass.Create;
var b: TAnotherClass;
b := a.Foo;

Unfortunatelly Delphi Web Script doesn't recognize the return value from TMyClass.Foo as a valid Script Class. Is there a possibility to do that without falling back to manually expose each method with an OnEval-Eventhandler?

Upvotes: 2

Views: 952

Answers (1)

Eric Grange
Eric Grange

Reputation: 6211

ExposeRTTI currently doesn't support parameters of class type.

This is because returning a direct Delphi class in the script can be problematic, as the life-cycle of Delphi objects is arbitrary and undetermined (the Delphi-side object can be destroyed at any time without notice f.i.).

You don't have to expose each method manually, you can use the RTTI exposer for every methods that involves basic types, and only have to deal manually with methods involving class types.

That'll then leave you with having to decide how you want the script-side objects to be exposed, and what their relationship to the Delphi-side object is, which is something the RTTI provides no clues about.

For instance with your original code, the OnEval code would just create a new script object that wraps the method Result for each call.

But the RTTI signature of Foo would still be exactly the same if its implementation was changed to something like

TMyClass = class
   private
      FFoo: TAnotherClass;
   public
      function Foo: TAnotherClass;
end;

function TMyClass.Foo: TAnotherClass;
begin
   if FFoo=nil then
      FFoo := TAnotherClass.Create;
   Result := FFoo;
end;

However in that case, the OnEval would have to be completely different, as you would have to return the same script-side object on subsequent calls, and you would also need to hook the script-side object's destructor to properly handle the consequences on the private FFoo field.

Once Delphi has truly garbage-collected objects, the constraint could be relaxed, but currently the only thing that gets close is TInterfacedObject, which is unsafe, and you still have to deal with manual event handlers to handles things like circular references or classes that disable the reference counting (like the VCL components).

Upvotes: 2

Related Questions