saastn
saastn

Reputation: 6015

Forward declarations for record types (or arrays)

I want to do this in XE5:

type
  TMyRec = record
    // fields
    class function GetList: TMyRecArr; static;
  end;

  TMyRecArr = array of TMyRec;

I've already seen "Forward declarations for record types" and "how to do a typed forward declaration?", but they seem irrelevant since my problem is not passing the record as a parameter.

Upvotes: 12

Views: 12239

Answers (4)

PatrickvL
PatrickvL

Reputation: 4164

Instead of trying to add forward decalrations to records (which up until now still isn't possible in Delphi), there is a way around this : move functions that reference another record type towards a record helper, declared where both record types are in scope.

type
  RecordA = record
    // [...]
  end;

  RecordB = record
    // [...]
  end;

  RecordAHelper = record helper for RecordA
    procedure Call(argument: RecordB);
  end;

After obvioulsy implementing this, above allows one to write (and compile and run) : RecordA_variable.Call(RecordB_variable)

Upvotes: 0

saastn
saastn

Reputation: 6015

Well, I searched a little more, and found that I can use helpers to do this:

type
  TMyRec = record
    // fields
  end;

  TMyRecArr = array of TMyRec;

  TMyRecHelper = record helper for TMyRec
    class function GetList: TMyRecArr; static;
  end;

Sure it lacks benefits of generics that David mentioned in his answer and comments, but it doesn't make the code auto-complete unusable! I mean one may comes to this conclusion that the flexibility that TArray<T> offers is not needed in some piece of code. Then it would be nothing more than increment in memory usage of the final running application or possibly lower performance.

Upvotes: 0

fantaghirocco
fantaghirocco

Reputation: 4878

Since declarations of pointers types are permitted before the type definition, slightly modifying your function you're allowed to do this:

type
  PMyRecArr = ^TMyRecArr;

  TMyRec = record
    // fields
    class procedure GetList(const arr: PMyRecArr); static;
  end;

  TMyRecArr = array of TMyRec;

The procedure implementation and its usage follow:

class procedure TMyRec.GetList(const arr: PMyRecArr);
begin
  SetLength(arr^, 4);
end;

var
  arr: TMyRecArr;

begin
  TMyRec.GetList(@arr);
  Writeln(Length(arr));//prints 4
end.

Upvotes: 1

David Heffernan
David Heffernan

Reputation: 613252

You cannot use a forward declaration to declare a record type or an array type. But not to fear. You can use a generic dynamic array, TArray<T>.

type
  TMyRec = record
    class function GetList: TArray<TMyRec>; static;
  end;

This is actually better than declaring TMyRecArr as per the code in your question. That's because the generic TArray<T> has more flexible type identity than a traditional dynamic array type. You can use TArray<T> with generic types defined in libraries that are independent and unaware of your code.

Now, you could declare the type like this:

type
  TMyRec = record
    type TMyRecArray = array of TMyRec;
    class function GetList: TMyRecArray; static;
  end;

And then your array type is TMyRec.TMyRecArray. But I urge you not to do this. You'll have a type that can only be used with you code, and cannot be used with third party code.

In summary, TArray<T> is your friend.

Upvotes: 19

Related Questions