Saturday, May 16, 2020

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.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.