Computing: Free Pascal Programming

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.