Record return function with interface field

After asking this question about the fields of the interface in the entries, I assumed that the following would work (note the statement):

type TRec <T> = record Intf : IInterface; end; TTestClass = class public function ReturnRec : TRec <Integer>; end; // Implementation function TTestClass.ReturnRec : TRec <Integer>; begin Assert (Result.Intf = nil); // Interface field in record should be initialized! Result.Intf := TInterfacedObject.Create; end; 

I checked this with the following code:

  for I := 1 to 1000 do Rec := Test.ReturnRec; 

and the statement is not fulfilled!

Where is my mistake here? Which assumption is wrong?

+8
delphi delphi-xe
source share
1 answer

Function

 function ReturnRec: TRec<Integer>; 

Semantically equal to procedure

 procedure ReturnRec(var Result: TRec<Integer>); 

[I’m pretty sure that someone from Embarcadero, probably Barry Kelly or Alan Bauer, stated this somewhere, but I can’t find the link for now.]

In the second case, the compiler assumes that the record will be initialized (if necessary) before it is passed to ReturnRec, and will not generate any initialization code for rec inside ReturnRec. I assume that the same code path inside the compiler is taken for the first example and why the result is not initialized.

In any case, the solution is simple:

 function TTestClass.ReturnRec : TRec <Integer>; begin Result.Intf := TInterfacedObject.Create; end; 

Suppose the compiler knows what it does and assigns an interface, and everything will work fine.

EDIT

The problem that arises comes from the 'for' loop. Your code

 for I := 1 to 1000 do Rec := Test.ReturnRec; 

consists of the following:

 var result: TRec<Integer>; Initialize(result); for I := 1 to 1000 do begin Test.ReturnRec(result); rec := result; end; 

This is why you reuse the same entry, and therefore Result.Intf is not initialized only the first time.

EDIT2

You can trick the compiler by moving t.ReturnRec to call from the loop into a separate method.

 procedure GetRec(t: TTest; var rec: TRec); begin rec := t.ReturnRec; end; for i := 1 to 1000 do GetRec(t, rec); 

Now the hidden result variable lives in the GetRec procedure and is initialized every time GetRec is called.

+12
source share

All Articles