5
votes

I assume that my question may already exist in SO knowledgebase and I just couldn't find it. In this case, please guide me to the origin and vote to close this one as a duplicate. It is about passing array parameters to a procedure.

The below case is simple, intuitive and working:

procedure MyProc(const A: array of ShortString);
begin
//
end

Now I can call MyProc and directly pass strings to it:

MyProc(['no', 'trump', 'please']);

Now what if I declare a type of array of ShortString?

type
  TMyArray = array of ShortString;

procedure MyProc(const A: TMyArray);
begin
//
end

Is there any way to execute MyProc passing parameters of array type directly? I.e. using the same procedure call as above.

+bonus question:

type TMyRecord = record
  param, value: ShortString
end;

procedure MyProc(const R: TMyRecord);
begin
//
end

Is there any technique to call a procedure and pass values of a type record? Something like (pseudocode):

MyProc((TMyRecord.param='aaa', TMyRecord.value='bbb'));

The reason I ask: I don't want to declare a variable and set it up. Instead I want to pass array/record values directly as a procedure parameter.

2
There is a difference between open array parameters and dynamic arrays, althogh their synatx is pretty similar. More in my article about this. Records can only be passed that way if you delcare a function that creates themRudy Velthuis
If you ever need to debug this you will have wished you declared a variable and set it up...GuidoG
One question also a time please. And why are you using short strings?David Heffernan
@David Heffernan, I use Delphi 10.1 Berlin which has a known issue (RSP-14914): if you declare array of string Code Insight stops functioning. An an alternative for this particular example I used short strings which do not stop the show.Interface Unknown
Bad move. Now you don't support Unicode and performance is affected. Don't worry about code insight.David Heffernan

2 Answers

5
votes

As others said, it can be done in Delphi XE7 and later. In previous versions, array types can't be passed directly as parameter.

If you can't do without this "comfort".. As an "ugly" solution, you could use an intermediate function which copies a dynamic array into its corresponding array type:

function AsTypeArray(const MyArray : array of ShortString) : TMyArray;
begin
  SetLength(Result, Length(MyArray));
  Move(MyArray[Low(MyArray)], Result[0], Length(MyArray) * SizeOf(MyArray[Low(MyArray)]));
end;

So you could write:

MyProc(AsTypeArray(['no', 'trump', 'please']));

I don't like this solution, but if you can't upgrade to Delphi XE7 or later and you absolutely want to pass array type parameters directly, I think this is the only way.

Note that you can pass TMyArray objects as parameters to functions defined for accepting dynamic arrays:

procedure MyProc(const A: array of ShortString);
//...

var
  Arr : TMyArray;
begin
  //...
  MyProc(Arr); //It won't raise any error/warning
end;

Also for records, an intermediate function which returns the record type is needed.

function MyRecord(Param : ShortString; Value : ShortString) : TMyRecord;
begin
  Result.Param := Param;
  Result.Value := Value;
end;

Then you'll be able to pass your record without declaring a variable.

MyProc(MyRecord('aaa', 'bbb'));

Also in last Delphi's versions, I think there's no other way.

4
votes

Yes, what you have written works in Delphi XE7 and higher.

program Project1;

{$APPTYPE CONSOLE}

type
  TMyArray = array of ShortString;

procedure MyProc(const A: TMyArray);
var
  s : ShortString;
begin
  for s in A do WriteLn(s);
end;

begin
  MyProc(['no', 'trump', 'please']);
  ReadLn;
end.

Output :

no
trump
please

XE7 introduced new dynamic array initialization syntax that allows function calls like the one above. Prior to that you need to initialize with an explicit constructor like :

 MyProc(TMyArray.Create('no', 'trump', 'please'));

For the record, you need a constructor or other method to return the record type. This works :

program Project1;

{$APPTYPE CONSOLE}

type
  TMyRecord = record
   param: ShortString;
   value: ShortString;
   constructor Create(AParam, AValue : ShortString);
  end;

constructor TMyRecord.Create(AParam: ShortString; AValue: ShortString);
begin
  param := AParam;
  value := AValue;
end;

procedure MyProc(const R: TMyRecord);
begin
  WriteLn(R.param);
  WriteLn(R.value);
end;

begin
  MyProc(TMyRecord.Create('foo', 'bar'));
  ReadLn;
end.

Output:

foo
bar