3

In Delphi 10.3, I had written some Excel automation code. I used variants. When the routine was finished, I cleared and freeAndNil the Variant...

  VarClear(arrData);
  FreeAndNil(arrData);

This compiled and ran fine. I have just upgraded to D11, i.e. Alexandria. This code now gives an error. ... Incompatible Type: TObject and Variant.

I rewrote this portion of code to be:

  VarClear(arrData);
  arrData.Free;

This compiles, and at first glance, seems to run fine. Is this the proper way to clear/dispose of variants in Alexandria?

user1009073
  • 3,160
  • 7
  • 40
  • 82
  • I don't have D11, but based on your description, they redefined `FreeAndNil(var obj)` to `procedure FreeAndNil(var Obj:TObject)`. Now, since `Free` is a method of TObject and unrelated to variant, unless they added helpers for variants that introduce a "free" method, that looks awfully wrong to me. – Ken Bourassa Jan 11 '22 at 19:30

3 Answers3

14

The signature of FreeAndNil() was indeed changed, in Delphi 10.4, to be exact:

https://blog.marcocantu.com/blog/2020-may-delphi-104-rtl.html

We updated the signature of the FreeAndNil procedure, to avoid its use with interface references and other unsupported data types. It is now declared to require a reference to a TObject:

procedure FreeAndNil(const [ref] Obj: TObject); inline;

This means that incorrect usage of FreeAndNil will now cause a compiler error. In the past, incorrect usage would not be caught, leading to difficult bugs. Note that although the parameter is declared as const, the by-reference variable is indeed modified.

It is wrong to try to Free() a Variant in the first place. That has never worked, and should never have been in your code in the first place. Under the old definition, FreeAndNil() would have called TObject.Free() on the Variant, which is wrong. Under your new code, arrData.Free; will compile, but will invoke method dispatching at runtime to call a non-existent Free() method on the Excel object, which will fail.

So, just remove the Free altogether, it doesn't belong here. The correct solution, in all Delphi versions, to manually reset a Variant to a default state is to assign Variants.Null or Variants.Unassigned to it, eg:

arrData := Null;
arrData := Unassigned;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Excellent Answer! – user1009073 Jan 12 '22 at 19:08
  • FreeAndNil does (falsely) not complain when called in a (object type) property. This is painfully wrong, Emb has traded a bad solution for another bad solution. See https://stackoverflow.com/questions/62479148/ – H.Hasenack Jan 12 '22 at 21:56
6

Both of these code snippets are wrong. You don't call Free on a variant. You call Free on an object instance. Simply remove that line.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
0

if the variable is a pointer array FreeAndNil is not the solution. but freemem

FreeMem(PSomeArray);
Zen Of Kursat
  • 2,672
  • 1
  • 31
  • 47