Tuesday, March 10, 2020

How to Return Multiple Values From a Delphi Function

How to Return Multiple Values From a Delphi Function A most common construct in a Delphi application would be a procedure or a function. Known as routines, procedures or functions are statement blocks you call from different locations in a program. Simply put a procedure is a routine not returning a value while a function returns a value. A return value from a function is defined by the return type. In most cases you would write a function to return a single value that would be an integer, string, boolean or some other simple type, also return types could be an array, a string list, an instance of a custom object or alike. Note that even if your function returns a string list (a collection of strings) it still returns a single value: one instance of the string list. Further, Delphi routines can really have many faces: Routine, Method, Method Pointer, Event Delegate, Anonymous method... Can a Function Return Multiple Values? The first answer that comes to mind is no, simply because when we think of a function, we think of a single return value. Certainly, the answer to the above question is, however, yes. A function can return several values. Lets see how. Var Parameters How many values can the following function return, one or two? function PositiveReciprocal(const valueIn : integer; var valueOut : real): boolean; The function obviously returns a boolean value (true or false). How about the second parameter valueOut declared as a VAR (variable) parameter? Var parameters are passed to the function by reference meaning that if the function changes the value of the parameter- a variable in the calling block of code- the function will change the value of the variable used for the parameter. To see how the above works, heres the implementation: function PositiveReciprocal(const valueIn: integer; var valueOut: real): boolean;begin result : valueIn 0; if result then valueOut : 1 / valueIn;end; The valueIn is passed as a constant parameter- function cannot alter it, and it is treated as read-only. If valueIn or greater than zero, the valueOut parameter is assigned the reciprocal value of valueIn and the result of the function is true. If valueIn is 0 then the function returns false and valueOut is not altered in any way. Heres the usage: var b : boolean; r : real;begin r : 5; b : PositiveReciprocal(1, r); //here: // b true (since 1 0) // r 0.2 (1/5) r : 5; b : PositiveReciprocal(-1, r); //here: // b false (since -1 end; Therefore, the PositiveReciprocal actually can return 2 values! Using var parameters you can have a routine return more than one value. Out Parameters Theres another way to specify a by-reference parameter- using the out keyword, as in: function PositiveReciprocalOut(const valueIn: integer; out valueOut: real): boolean;begin result : valueIn 0; if result then valueOut : 1 / valueIn;end; The implementation of PositiveReciprocalOut is the same as in PositiveReciprocal, theres only one difference: the valueOut is an OUT parameter. With parameters declared as out, the initial value of the referenced variable valueOut is discarded. Heres the usage and the results: var b : boolean; r : real;begin r : 5; b : PositiveReciprocalOut(1, r); //here: // b true (since 1 0) // r 0.2 (1/5) r : 5; b : PositiveReciprocalOut(-1, r); //here: // b false (since -1 end; Note how in the second call the value of the local variable r is set to 0. The value of r was set to 5 before the function call but since the parameter in declared as out, when r reached the function the value was discarded and the default empty value was set for the parameter (0 for real type). As a result, you can safely send uninitialized variables for out parameters- something that you should not do with var parameters. Parameters are used to send something to the routine, except here with out parameters :), and therefore uninitialized variables (used for VAR parameters) could have weird values. Returning Records? The above implementations where a function would return more than one value are not nice. The function actually returns a single value, but also returns, better to say alters, the values of the var/out parameters. Because of this, you may very rarely want to use by-reference parameters. If more results from a function are required, you can have a function return a record type variable. Consider the following: type TLatitudeLongitude record Latitude: real; Longitude: real; end; and a hypothetical function: function WhereAmI(const townName : string) : TLatitudeLongitude; The function WhereAmI would return the Latitude and Longitude for a given town (city, area, ...). The implementation would be: function WhereAmI(const townName: string): TLatitudeLongitude;begin//use some service to locate townName, then assign function result: result.Latitude : 45.54; result.Longitude : 18.71;end; And here we have a function returning 2 real values. Ok, it does return 1 record, but this record has 2 fields. Note that you can have a very complex record mixing various types to be returned as a result of a function. Thats it. Therefore, yes, Delphi functions can return multiple values.