user1009073
user1009073

Reputation: 3238

Delphi - Why Use VarArrayPut?

I am using Delphi Rio to control Excel. I am reading and writing whole columns, so I am using VarArrayCreate to create an array of variant to read a column's worth of data. I update specific portions of the data, and then write the update back to the Variant array. When done, I write the whole Variant array back to my column.

While looping through the array, I read a single element of the array.... and potentially write back to that element of the array...

... read from the array
CellText := arrData[i, 1];

... possibly update data

... write the updated data back to the array
arrData[i,1] := CellPadded;

This works without issue. My question has to do with writing the update back to the array. I ran into the function VarArrayPut. Why would I use this as opposed to directly putting the data back into the array like in the code above?

Upvotes: 2

Views: 322

Answers (1)

Peter Wolf
Peter Wolf

Reputation: 3830

The simple answer is that VarArrayPut is the same as array accessor (square brackets syntax) and in the end they both invoke internal procedure _VarArrayPut in unit System.Variants. Likewise reading value from the array using square brackets or VarArrayGet will result in a call to internal function _VarArrayGet. You can easily check that yourself by stepping into (F7) the assignment arrData[i, 1] := CellPadded; during a debugging session.

That said, the variant array accessor is just a syntactic sugar that Delphi compiler provides to make the code shorter and more readable, but that is a subject of personal taste. Consider the following:

arrData[i, 1] := CellPadded;
{ vs }
VarArrayPut(arrData, CellPadded, [i, 1]);

In case you do a lot of data manipulation and you're not resizing the array during the processing you might as well do it in a VarArrayLock .. VarArrayUnlock block to gain some extra performance by direct access to array data bypassing all the sanity checks and API calls that _VarArrayGet and _VarArrayPut do internally:

{ untested, use at your own risk }
{$POINTERMATH ON}
var
  Data: PVariant; { in case of variant array of varVariant }
  LBound1, LBound2, HBound2: Integer;

Data := VarArrayLock(arrData);
try
  LBound1 := VarArrayLowBound(V, 1);
  LBound2 := VarArrayLowBound(V, 2);
  HBound2 := VarArrayHighBound(V, 2);
  { access element value at [i, j] }
  (Data + i - LBound1 + (j - LBound2) * (HBound2 - LBound2 + 1))^ := CellPadded;

  { ... }

finally
  VarArrayUnlock(arrData);
end;

This won't of course work with jagged arrays.

Upvotes: 7

Related Questions