Sooner or later, any programmer is consumed using procedures and functions. We all remember from Pascal that there is nothing complicated there, but some things are usually not described in books, although it is required to know in order to write a program correctly.
Parentheses
Adding parentheses when calling procedures and functions without parameters is no longer a novelty in Delphi, however, this feature is little known. This opportunity will be appreciated by those programmers who have to work in two languages (C ++ and Delphi), since they will not need to constantly remember the difference in syntax when calling procedures and functions in different languages. In Delphi, both of the options below are considered valid.
Form1.Show;
Form1.Show();
Overload capability
For the first time, the concept of overloading procedures and functions was implemented in Delphi 4. It allows you to have several different procedures and functions with the same name, but with different lists of parameters. Such procedures and functions should be described using the overload directive.
procedure Test (I: integer); overload;
procedure Test (S: string); overload;
procedure Test (D: double); overload;
When you call the Test procedure, Delphi will decide which of the three procedures to perform, depending on the parameter passed to it. But it should be noted that this is not the safest language option. The use of overloaded procedures and functions can be an inexhaustible source of subtle errors in the program. Therefore, use this opportunity carefully.
')
Parameter passing
Pascal allows you to pass parameters to functions and procedures, either by value or by reference. The passed parameter can be of any built-in or user-defined type or be an open array. A parameter can also be a constant if its value in a procedure or function does not change.
Passing parameters by value
This parameter transfer mode is the default. If the parameter is passed by value, a local copy of this variable is created, which is provided for processing into a procedure or function. Look at the following example:
procedure Test(s: string);
When calling this procedure, a copy will be created of the string s transmitted to it as a parameter, with which the Test procedure will work. In this case, all changes made to the string will not affect the initial variable s.
However, this does not apply to objects. For example, if a variable (or rather, an object instance) of TStringList is passed to the function, then in this case, a reference will be sent (even if this is not explicitly indicated). This method of transmission is the most favorite among most, but at the same time it is also the most unpractical, since to execute the method, additional memory is allocated to create an exact copy of the variable passed. To solve this problem, use one of the methods described below.
Passing parameters by reference
Pascal also allows you to pass parameters to functions or procedures by reference - such parameters are called variable parameters. Passing a parameter by reference means that the function or procedure can change the values of the parameters obtained. To pass parameters by reference, the var keyword is used, which is placed in the parameter list of the called procedure or function.
procedure ChangeMe(var x: longint);
begin
x := 2; //
end;
Instead of creating a copy of the variable x, the var keyword requires passing the address of the variable x itself, which allows the procedure to directly change its value.
Passing Constant Parameters
If there is no need to change the data passed to the function or procedure, you can describe the parameter as a constant. The const keyword not only protects the parameter from being modified, but also allows the compiler to generate a more optimal code for passing strings and records. Here is an example of a constant parameter declaration:
procedure Test(const s: string );
Passing open arrays
An open array of parameters allows you to transfer a different number of parameters to a function or procedure. As parameters, you can pass either an open array of elements of the same type, or arrays of constants of various types. In the example below, a function is declared, to which an open array of integers should be passed as a parameter.
function AddEmUp(A: array of integer): integer;
In an open array, you can pass variables, constants, or expressions from constants.
You can use the High, Low, and SizeOf functions to get information about the actual array of parameters in a function or procedure.
Object Pascal also supports the type of array of const, which allows you to transfer data of different types in one array. The syntax for declaring functions or procedures using such an array to get parameters is as follows:
procedure WhatHaveIGot( A: array of const );
You can call the function declared above, for example, using the following operator:
procedure WhatHaveIGot( ['Text', 10, 5.5, @WhatHaveIGot, 3.14, true, 'c'] );
When passing a function or procedure to an array of constants, all the parameters passed to the compiler implicitly convert to the type TVarRec. The TVarRec data type is declared in the System module as follows:
PVarRec = ^TVarRec;
TVarRec = record
case Byte of
vtInteger: (VInteger: Integer; VType: Byte);
vtBoolean: (VBoolean: Boolean);
vtChar: (VChar: Char);
vtExtended: (VExtended: PExtended);
vtString: (VString: PShortString);
vtPointer: (VPointer: Pointer);
vtPChar: (VPChar: PChar);
vtObject: (VObject: TObject);
vtClass: (VClass: TClass);
vtWideChar: (VWideChar: WideChar);
vtPWideChar: (VPWideChar: PWideChar);
vtAnsiString: (VAnsiString: Pointer);
vtCurrency: (VCurrency: PCurrency);
vtVariant: (VVariant: PVariant);
vtInterface: (VInterface: Pointer);
vtWideString: (VWideString: Pointer);
vtInt64: (VInt64: PInt64);
end;
The VType field defines the type of data contained in this instance of the TVarRec record and can take one of the given values.
Since an array of constants is capable of transferring data of different types, this can cause certain difficulties in creating a function or procedure that processes the received parameters. As an example of working with such an array, consider the implementation of the WhatHaveIGot procedure, which looks at the elements of the resulting array of parameters and displays their type.
procedure WhatHaveIGot( A: array of const );
var
i: integer;
TypeStr: string;
begin
for i := Low(A) to High(A) do
begin
case A[i].VType of
vtInteger : TypeStr := 'Integer';
vtBoolean : TypeStr := 'Boolean';
vtChar : TypeStr := 'Char';
vtExtended : TypeStr := 'Extended';
vtString : TypeStr := 'String';
vtPointer : TypeStr := 'Pointer';
vtPChar : TypeStr := 'PChar';
vtObject : TypeStr := 'Object';
vtClass : TypeStr := 'Class';
vtWideChar : TypeStr := 'WideChar';
vtPWideChar : TypeStr := 'PWideChar';
vtAnsiString : TypeStr := 'AnsiString';
vtCurrency : TypeStr := 'Currency';
vtVariant : TypeStr := 'Variant';
vtInterface : TypeStr := 'Interface';
vtWideString : TypeStr := 'WideString';
vtInt64 : TypeStr := 'Int64';
end;
ShowMessage( Format( 'Array item %d is a %s', [i, TypeStr] ) );
end;
end;
Default Parameter Values
In Delphi there is one very useful feature - the use of default parameter values. It allows you to set the default value of a parameter of a procedure or function. This value will be used in cases when the procedure or function is called without specifying the value of this parameter. In the declaration of a procedure or function, the default value of the parameter is indicated after the equal sign following the name of the parameter. We explain this with the following example:
procedure HasDefVal( s: string; i: integer = 0 );
Similar declaration means that the HasDefVal procedure can be called in two ways. In the first case - as usual, with the indication of both parameters:
procedure HasDefVal( 'Hello', 26 );
In the second case, you can specify only the value of the s parameter, and for the i parameter, use the default value:
procedure HasDefVal( 'Hello' );
When using the default settings, remember a few of the rules below:
- Parameters that have default values should be placed at the end of the parameter list. A parameter without a default value should not appear in the list after a parameter that has a default value.
- Default values can only be assigned to parameters of ordinary types, pointers or sets.
- The default value can be transmitted only by value or with the const modifier. It cannot be a reference or an untyped parameter.
One of the important advantages of using the default parameter values is the ease of extending the functionality of existing procedures and functions while maintaining backward compatibility. Suppose a program was launched on the software market, the key element of which is the addition function of two integer values:
function Add( I1, I2: integer ): integer;
begin
Result := I1 + I2;
end;
Suppose also that studies have shown the feasibility of adding to the program the possibility of adding three numbers. However, replacing the existing function with the addition function of three numbers will lead to the fact that you will have to forward a lot of text, which will cease to be compiled due to the addition of one more parameter to the function. However, using default parameter values, the problem is solved easily and simply. It is enough to change the declaration of the function as shown below.
function Add( I1, I2: integer; I3: integer = 0 ): integer;
begin
Result := I1 + I2 + I3;
end;
Directive {$ X-}
The {$ X-} directive prohibits calling functions as procedures (ignoring the return result). By default, this mode is enabled ({$ X +}). So, remember, the use of the Result variable is unacceptable when the option Extended Syntax is unchecked, located in the Compiler tab of the Project Options dialog box, or when specifying the compiler directive {$ X-}.
In each function of the Objecl Pascal language, there is a local variable called Result, designed to accommodate the return value. In addition, you can also return a value from a function by assigning a value to a variable that has the same name as this function. This is the standard syntax of the Pascal language, preserved from its previous versions. When using a variable with its name in the function body, do not forget that there are big differences in the processing of this name - it all depends on where it is located - on the left side of the assignment operator or in any other place of the function text. If the function name is indicated on the left side of the assignment operator, it is assumed that the return value is assigned by the function. In all other cases, it is assumed that a recursive call to this function is made.
Procedure and function are key concepts in any programming language, without which no serious program can do. And so it is very important to have a full understanding of the mechanism of their work.