5

(EDIT: This is following on from Are objects reference counted in Windows-targeted Delphi applications, and if so, what is its purpose? and Dynamic arrays and memory management in Delphi).

I have two classes (TGenericHoldingSummary, TGenericHoldingResultSet) and one record (TGenericHoldingResult).

  • TGenericHoldingSummary contains a single TGenericHoldingResultSet, which is set to nil and lazy-loaded from the database if and when required.
  • The TGenericHoldingResultSet contains a dynamic array of TGenericHoldingResult records.

In the below, the error is at the assignment in the TGenericHoldingResultSet constructor.

TGenericHoldingResult = record
  code : Integer;
  level : String;
  msg : String;
end;

TGenericHoldingResultSet = class(TObject)
  public
    // Lifecycle
    constructor Create(parent : TGenericHoldingSummary; resArr : Array of TGenericHoldingResult);
    destructor Destroy;
    // Accessors
    function ResultCount() : Integer;
    function Result(i : Integer) : TGenericHoldingResult;
  private
    // Variables
    summary : TGenericHoldingSummary;
    resultArray : Array of TGenericHoldingResult;
end;

TGenericHoldingSummary = class(TObject)
public
  // Note that the summary object 'owns' the results, and deallocates
  // its memory in the destructor.
  function getResultSet: TGenericHoldingResultSet;
private
  // Member variables
  resultSet: TGenericHoldingResultSet;
end;

// Note that the summary object 'owns' the results, and deallocates
// its memory in the destructor.
function TGenericHoldingSummary.getResultSet() : TGenericHoldingResultSet;
var
  sql : String;
  i : Integer;
  resultArray : Array of TGenericHoldingResult;
begin
  if resultSet = nil then
  begin
    // Get results via SQL.
    SetLength(resultArray, holding.clientDataSet.RecordCount);

    for i := 0 to holding.clientDataSet.RecordCount - 1 do
    begin
      resultArray[i].code := holding.clientDataSet.FieldByName('code').AsInteger;
      resultArray[i].level := holding.clientDataSet.FieldByName('level').AsString;
      resultArray[i].msg := holding.clientDataSet.FieldByName('message').AsString;
    end;

    resultSet := TGenericHoldingResultSet.Create(self, resultArray);
  end;

  result := resultSet;
end;

// Lifecycle
constructor TGenericHoldingResultSet.Create(parent : TGenericHoldingSummary; resArr : Array of TGenericHoldingResult);
begin
  summary := parent;
  // The following *should* work, shouldn't it?
  // E.g., seeing as dynamic arrays a reference counted in Delphi for
  // all platforms, this should simply increment the reference count.
  resultArray := resArr;
end;

The error is below:

[DCC Error] GenericHolding.pas(302): E2010 Incompatible types: 'Dynamic array' and 'Array'
Community
  • 1
  • 1
magnus
  • 4,031
  • 7
  • 26
  • 48

1 Answers1

6

You cannot assign an open array to a dynamic array. See Open Array Parameters.

Note: The syntax of open array parameters resembles that of dynamic array types, but they do not mean the same thing. The previous example creates a function that takes any array of Char elements, including (but not limited to) dynamic arrays. To declare parameters that must be dynamic arrays, you need to specify a type identifier:

type TDynamicCharArray = array of Char;
function Find(const A: TDynamicCharArray): Integer;

A good summary of the use case of open arrays and the difference with a dynamic array can be found here: Open array parameters.


If you have a Delphi version that supports generics, it is possible to declare the constructor header:

constructor TGenericHoldingResultSet.Create(parent : TGenericHoldingSummary; 
  const resArr : TArray<TGenericHoldingResult>);

and your resultArray as TArray<TGenericHoldingResult>.

This will avoid having to declare a specific type for the array.

As noted by David, open arrays have a benefit since they have a broader use case, and should be used when possible.

LU RD
  • 34,438
  • 5
  • 88
  • 296
  • That is helpful, but now I am receiving another error. I have changed the added the type `TGenericHoldingResultDynamicArray = Array of TGenericHoldingResult;` and changed the parameters, but now receive a different error on the assignment line `[DCC Error] GenericHolding.pas(261): E2010 Incompatible types: 'TGenericHoldingResultDynamicArray' and 'Dynamic array'`. – magnus Mar 03 '14 at 07:03
  • The resultArray must be declared as `TGenericHoldingResultDynamicArray` as well. – LU RD Mar 03 '14 at 07:05
  • No, it is strongly typed, which is to the benefit of the programmer. – LU RD Mar 03 '14 at 07:10
  • 1
    It is better not to declare a new type, and to instead use the generic syntax `TArray`. Generics have more flexible type compatibility. Through necessity. You can use that to your advantage when dealing with arrays. – David Heffernan Mar 03 '14 at 07:11
  • @LURD My issue is not with strong typing. E.g., in C++ using an "enum class" for strongly typed "enum". However, I do find the identical syntax used for dynamic arrays and open arrays an unnecessary and confusing language design decision. – magnus Mar 03 '14 at 08:03
  • @user That's how languages are. They develop. Open arrays come from a previous age. There are a lot of confusing things in C++ too. You probably don't see that so much since you are fluent in C++. I find C++ more confusing than Delphi but I know that is primarily a statement about me. – David Heffernan Mar 03 '14 at 08:28
  • @David. Fair comment. Perhaps my impression of the language is additionally influenced by the fact that my workplace is a Delphi shop (since around Delphi 5) and yet the concept of open arrays is unknown. But again, that may be due to cultural factors. – magnus Mar 03 '14 at 08:50
  • 1
    @user I think a lot of Delphi developers that don't know better use dynamic arrays as parameters in situations where open arrays would be better. The advantage of open arrays is that they are more flexible. They can accept more than just dynamic arrays. Now, there are times where parameters should be dyn arrays, but if an open array can be used, it should be used. – David Heffernan Mar 03 '14 at 08:54
  • An article by @RudyVelthuis explains more about [`Open array parameters`](http://rvelthuis.de/articles/articles-openarr.html). It should be updated though, to mention generic arrays as well. – LU RD Mar 03 '14 at 12:25