After asking this question about interface fields in records I assumed that the following would work (notice the assertion):
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 tested this with the following code:
for I := 1 to 1000 do
Rec := Test.ReturnRec;
and the assertion fails!
Where's my mistake here? What assumption is wrong?
Function
function ReturnRec: TRec<Integer>;
Is semantically equal to procedure
procedure ReturnRec(var Result: TRec<Integer>);
[I'm pretty sure that somebody from Embarcadero, probably Barry Kelly or Alan Bauer stated this somewhere but I can't find the reference at the moment.]
In the second case, the compiler assumes that the record will be initialized (if necessary) before it is passed to the ReturnRec and doesn't create any initialization code for rec inside ReturnRec. I'm assuming that the same code path inside compiler is taken for the first example and that's why the Result is not initialized.
Anyway, the solution is simple:
function TTestClass.ReturnRec : TRec <Integer>;
begin
Result.Intf := TInterfacedObject.Create;
end;
Just assume that compiler knows what it's doing and assign the interface and everything will work just fine.
EDIT
The problem you have occurs from the 'for' loop. Your code
for I := 1 to 1000 do
Rec := Test.ReturnRec;
is compiled into something like this:
var
result: TRec<Integer>;
Initialize(result);
for I := 1 to 1000 do begin
Test.ReturnRec(result);
rec := result;
end;
That is why you are reusing same record all over and that is why Result.Intf is uninitialized only the first time.
EDIT2
You can trick the compiler by moving t.ReturnRec call out 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With