Free Pascal functions with multiple return-values.
As a difference with programming languages as for example C, Free Pascal functions allow one single return value only. This is not a big deal, as Pascal includes a second subroutine type, the procedures, and you can use out arguments to return as many values as you want. If, for example, you want to write a subroutine that sorts an array of integers, with the original array as input, and the sorted array as output, you can create the corresponding procedure as in the following simple program:
program bubble_sort;
type
TArray = array of Integer;
var
I: Integer;
Arr1, Arr2: TArray;
// Bubble sort procedure
procedure Sort(var A1: TArray; out A2: TArray);
var
Temp, I, J: Integer;
begin
SetLength(A2, Length(A1)); A2 := A1;
for I := 0 to Length(A2) - 2 do begin
for J := I + 1 to Length(A2) - 1 do begin
if A2[I] > A2[J] then begin
Temp := A2[I]; A2[I] := A2[J]; A2[J] := Temp;
end;
end;
end;
end;
// Main program
begin
SetLength(Arr1, 10);
Arr1 := [2, 4, 8, 1, 9, 3, 6, 7, 5, 0];
Sort(Arr1, Arr2);
for I := 0 to Length(Arr2) - 1 do
Write(Arr2[I], ' ');
Writeln;
Write('ENTER to terminate '); Readln;
end.
Note: The usage of a custom data type (TArray) is mandatory, because: first, trying to use SetLength with a variable of type array of Integer would result in a "Type mismatch" error, and second with A1 and A2 being of type array of Integer, the statement A2 := A1 would result in an "Assignments to formal parameters and open arrays are not possible" error.
However, the functions in Free Pascal are well limited to a single return-value, but not to a scalar data type of the return-value. This means that functions may return structured values, such as arrays and records. And, there is no problem to declare our sort routine as a function, as shown in the program below:
program bubble_sort2;
type
TArray = array of Integer;
var
I: Integer;
Arr1, Arr2: TArray;
// Bubble sort function
function Sort(var A1: TArray): TArray;
var
Temp, I, J: Integer;
A2: TArray;
begin
SetLength(A2, Length(A1)); A2 := A1;
for I := 0 to Length(A2) - 2 do begin
for J := I + 1 to Length(A2) - 1 do begin
if A2[I] > A2[J] then begin
Temp := A2[I]; A2[I] := A2[J]; A2[J] := Temp;
end;
end;
end;
Result := A2;
end;
// Main program
begin
SetLength(Arr1, 10);
Arr1 := [2, 4, 8, 1, 9, 3, 6, 7, 5, 0];
Arr2 := Sort(Arr1);
for I := 0 to Length(Arr2) - 1 do
Write(Arr2[I], ' ');
Writeln;
Write('ENTER to terminate '); Readln;
end.
In fact, our example is just a special form of a single value return. But, an array return-value can also be used if the function "really" calculates two or more different values. Example: Consider a serial AC RLC circuit with known frequency (F), resistance (R), inductance (L) and capacitance (C), and lets write a function that calculates the total impedance of the circuit. As this impedance actually is a vector, this has to be a two return-values function, the first being the vector's amplitude and the second its angle, in other words, the impedance Z and the phase angle φ. As a Free Pascal function may only return one value, we can either use a procedure, or write 2 functions, or return a two-elements array, where the first element is the impedance, and the second is the phase angle. Here is a simple program that shows how to implement this:
program rlc;
type
TArray = array[0..1] of Real;
var
F, R, L, C, Z, Phi: Real;
Impedance: TArray;
// Serial RLC circuit function
function SerialImpedance(F, R, L, C: Real): TArray;
var
XL, XC: Real;
SerImp: TArray;
begin
XL := 2 * 3.14 * F * L;
XC := 1 / (2 * 3.14 * F * C);
// Impedance
SerImp[0] := Sqrt(Sqr(R) + Sqr(XL - XC));
// Phase angle
SerImp[1] := 360 * Arctan((XL - XC) / R) / (2 * Pi);
Result := SerImp;
end;
// Main program
begin
F := 80; R := 203; L := 0.8; C := 390E-6;
Impedance := SerialImpedance(F, R, L, C);
Z := Impedance[0]; Phi := Impedance[1];
Writeln('Impedance Z = ', Z:7:2);
Writeln('Phase angle phi = ', Phi:7:2);
Writeln;
Write('ENTER to terminate '); Readln;
end.
Note: The array returned by a function must have been defined as a custom data type (TArray in our case).
Lets extend the SerialImpedance function, also returning a textual indication concerning the phase shift between the current and the voltage. A first possibility would be to use a third real value functioning as a code, ex: 0 = in phase, -1 = current leads, 1 = current lags. However, it is possible to return real values and strings in the same array. All we have to do is to use an array of Variant (for details, cf. my tutorial Special data types: Variants, variant records, and variant arrays). Here is the code:
program rlc2;
uses
Variants;
type
TArray = array[0..2] of Variant;
var
F, R, L, C, Z, Phi: Real;
PhaseShift: string;
Impedance: TArray;
// Serial RLC circuit function
function SerialImpedance(F, R, L, C: Real): TArray;
var
XL, XC, P: Real;
SerImp: TArray;
begin
XL := 2 * 3.14 * F * L;
XC := 1 / (2 * 3.14 * F * C);
// Impedance
SerImp[0] := Sqrt(Sqr(R) + Sqr(XL - XC));
// Phase angle
SerImp[1] := 360 * Arctan((XL - XC) / R) / (2 * Pi);
// Phase shift
if SerImp[1] = 0 then
SerImp[2] := 'Current and voltage are in phase.'
else if SerImp[1] < 0 then
SerImp[2] := 'The current leads the voltage.'
else
SerImp[2] := 'The current lags the voltage.';
Result := SerImp;
end;
// Main program
begin
F := 90; R := 710; L := 0.1; C := 228E-6;
Impedance := SerialImpedance(F, R, L, C);
Z := Impedance[0]; Phi := Impedance[1];
PhaseShift := Impedance[2];
Writeln('Impedance Z = ', Z:7:2);
Writeln('Phase angle phi = ', Phi:7:2);
Writeln(PhaseShift);
Writeln;
Write('ENTER to terminate '); Readln;
end.
A better way to implement the function consists in using a record as return-value. Not only that Variant are said to be slow, but also, this gives us the possibility to label the different elements of the return structure (instead of using indexes). Here is the new code:
program rlc3;
type
TImpedance = record
Z, Phi: Real;
PhaseShift: string;
end;
var
F, R, L, C: Real;
Impedance: TImpedance;
// Serial RLC circuit function
function SerialImpedance(F, R, L, C: Real): TImpedance;
var
XL, XC: Real;
SerImp: TImpedance;
begin
XL := 2 * 3.14 * F * L;
XC := 1 / (2 * 3.14 * F * C);
with SerImp do begin
Z := Sqrt(Sqr(R) + Sqr(XL - XC));
Phi := 360 * Arctan((XL - XC) / R) / (2 * Pi);
if Phi = 0 then
PhaseShift := 'Current and voltage are in phase.'
else if Phi < 0 then
PhaseShift := 'The current leads the voltage.'
else
PhaseShift := 'The current lags the voltage.';
end;
Result := SerImp;
end;
// Main program
begin
F := 90; R := 710; L := 0.1; C := 228E-6;
Impedance := SerialImpedance(F, R, L, C);
with Impedance do begin
Writeln('Impedance Z = ', Z:7:2);
Writeln('Phase angle phi = ', Phi:7:2);
Writeln(PhaseShift);
end;
Writeln;
Write('ENTER to terminate '); Readln;
end.
If you find this text helpful, please, support me and this website by signing my guestbook.