26
votes

If I am trying to call a procedure which has a record type (not object) as a parameter, is it possible to somehow pass details of that parameter "inline" without having to declare a variable of that type first?

eg assume I have this simple record type:

type TMyRecord = record
  AString: string;
  AnInt: Integer;
end;

and this procedure declaration:

procedure MyProcedure(Rec: TMyRecord);

If I want to call MyProcedure do I have to declare a variable of type TMyRecord or can I do something like:

MyProcedure(TMyRecord("Test", 10));

That doesn't work (XE2) (get a compiler error about it expecting a ")").

So, can I do something like that? Or not possible.

Thanks

4
A war is going on below. I think that the ideal answer would be "There is no syntax to create an arbitrary record instance 'inline', but for any given record, you can achieve essentially the same level of convenience by [Brian's answer follows]"Andreas Rejbrand

4 Answers

19
votes

It is possible using the advanced record structure.

For more information about advanced records, see the Records (advanced) section in Delphi help.

This is a small prototype to see how it works in your case to preinitialize a record in a function/procedure call :

Type
  TRecord = record
   AString : String;
   AnInt : Integer;
   Constructor Create( Const s : String; i : Integer);
  end;

constructor TRecord.Create(const s: String; i: Integer);
begin
  AString := s;
  AnInt := i;
end;

procedure DoSomething( theRec : TRecord);
begin
  WriteLn(theRec.AString, ' ',theRec.AnInt);
end;

begin
  DoSomeThing( TRecord.Create('S',1));
  ReadLn;
end.

Looking at the Delphi RTL, see the definitions of the record types TPoint and TRect in unit system.types (XE2). They define some overloaded Create constructors, which are used in lots of places to preinitialize the record structures in function/procedure calls.

18
votes

The question you are asking relates to code readability and there is a solution that avoids having to create a variable. The VCL uses this solution with the records TPoint and TRect.

Consider the definition of TPoint:

type
  TPoint = record
    X,Y integer
  end;

To pass a TPoint to a procedure you might do:

var
  MyPoint : TPoint;

begin
  MyPoint.X := 5;
  MyPoint.Y := 7;
  DoSomething( MyPoint );
end;

This is fine but takes 3 lines when one is also possible using the factory function Point:

begin
  DoSomething( Point(5,7) );
end;

In Delphi, a function has been declared as follows:

function Point( X, Y : integer ) : TPoint;
begin
  Result.X := X;
  Result.Y := Y;
end;

You can then call this function 'inline' to create the record 'on the fly' to to quickly You will see the same has been provided for TRect etc. I often put such a factory function together with the record declaration as follows, even if I don't plan to use them yet:

type
  TMyRecord = record
    A : integer;
    B : string;
  end;

function MyRecord( A : integer; const B : string ) : TMyRecord;
begin
  Result.A := A;
  Result.B := B;
end;

Use of this technique can improved the readability of code and also ensures that you don't accidently omit setting a record element.

6
votes

Just having fun with John Easley's idea:

type TRec = record
  X: string;
  Y: Integer;
end;

procedure TestRec(const Rec: array of const);
var
  R: TRec;

begin
  R.X:= string(Rec[0].VUnicodeString);
  R.Y:= Rec[1].VInteger;
  ShowMessage(R.X + IntToStr(R.Y));
end;

procedure TForm1.Button7Click(Sender: TObject);
begin
  TestRec(['Test', 22]);
end;

It is possible to pass record fields as array of const parameters and assign these parameters to local record variable.

2
votes

It would be nice! But, no.

If passing things inline is really your objective, then perhaps Open Array Parameters would suit you.

Procedure MyProcedure(const Vars: Array of Variant);
begin
  ShowMessage(VarToStr(Vars[0])+'  '+VarToStr(Vars[1]));
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
   MyProcedure(['Test', 12]);
end;

You could also pass an Array of Const, which is basically an array of TVarRec which is a variant record that also includes type information as VType. This is fun stuff..

An excellent article can be found on Rudy's Delphi Corner here: Rudy's Delphi Corner, Open Array Parameters