The Delphi Language, Part 1 - Procedures and Functions
(Page 2 of 10 )
Because procedures and functions are fairly universal topics as far as programming languages are concerned, we won't go into a great deal of detail here. We just want to fill you in on a few unique or little-known features in this area.
Note - Functions with no return value (a void return in C# parlance) are called procedures, while functions returning some value are referred to as functions. Often, the term routine will be used to describe both procedures and functions, and the term method describes a routine within a class.
Parentheses in Calls One of the lesser-known features of the Delphi language is that parentheses are optional when calling a procedure or function that takes no parameters. Therefore, the following syntax examples are both valid:
Form1.Show; Form1.Show(); Granted, this feature isn't one of those things that sends chills up and down your spine, but it's particularly nice for those who split their time between Delphi and a language like C#, where parentheses are required. If you're not able to spend 100% of your time in Delphi, this feature means that you don't have to remember to use different function-calling syntax for different languages.
Overloading The Delphi language supports the concept of function overloading, that is, the ability to have multiple procedures or functions of the same name with different parameter lists. All overloaded methods are required to be declared with the overload directive, as shown here:
procedure Hello(I: Integer); overload;
procedure Hello(S: string); overload;
procedure Hello(D: Double); overload; Note that the rules for overloading methods of a class are slightly different and are explained in the section "Method Overloading."
Default Value Parameters Also supported in the Delphi language are default value parameters—that is, the ability to provide a default value for a function or procedure parameter and not have to pass that parameter when calling the routine. In order to declare a procedure or function that contains default value parameters, follow the parameter type with an equal sign and the default value, as shown in the following example:
procedure HasDefVal(S: string; I: Integer = 0); The HasDefVal() procedure can be called in one of two ways. First, you can specify both parameters:
HasDefVal('hello', 26); Second, you can specify only parameter S and use the default value for I:
HasDefVal('hello'); // default value used for I You must follow several rules when using default value parameters:
Parameters having default values must appear at the end of the parameter list. Parameters without default values cannot follow parameters with default values in a procedure or function's parameter list.
Default value parameters can be of an ordinal, string, floating point, pointer, or set type. Class, interface, dynamic array, procedural, and class references are also supported, but only when the default value is made equal to nil.
Default value parameters must be passed by value or as const. They cannot be reference ( var, out) or untyped parameters.
One of the biggest benefits of default value parameters is in adding functionality to existing functions and procedures without sacrificing backward compatibility. For example, suppose that you publish a unit containing a revolutionary function called AddInts() that adds two numbers:
function AddInts(I1, I2: Integer): Integer;
begin
Result := I1 + I2;
end; In order to keep up with the competition, you feel you must update this function so that it has the capability for adding three numbers. However, you're loathe to do so because adding a parameter will cause existing code that calls this function to not compile. Thanks to default parameters, you can enhance the functionality of AddInts() without compromising compatibility. Here's an example:
function AddInts(I1, I2: Integer; I3: Integer = 0);
begin
Result := I1 + I2 + I3;
end;
Tip - Generally, you should look to overloaded routines when choosing between the addition of default values or overloaded routines as a means to add new features without breaking backward compatibility. Overloads are executed a bit more efficiently and are more compatible with other .NET languages because default value parameters are not supported in C# or managed C++.
Variables You might be used to declaring variables off the cuff: "I need another integer, so I'll just declare one right here in the middle of this block of code." This is a perfectly reasonable notion if you're coming from another language such as C# or Visual Basic .NET. If that has been your practice, you're going to have to retrain yourself a little in order to use variables in the Delphi language. Delphi requires you to declare all variables up front in their own section before you begin a procedure, function, or program. Perhaps you used to write free-wheeling code like this:
public void foo()
{
int x = 1;
x++;
int y = 2;
float f;
//... etc ...
}
In Delphi, any such code must be tidied up and structured a bit more to look like this:
procedure Foo;
var
x, y: Integer;
f: Double;
begin
x := 1;
inc(x);
y := 2;
//... etc ...
end;
Case Sensitivity and Capitalization - The Delphi language—like Visual Basic .NET, but unlike C#—is not a case sensitive language. Upper- and lowercase is used for clarity's sake, so use your best judgment, as the style used in this book indicates. If the identifier name is several words mashed together, remember to camel-cap for clarity by capitalizing the first letter of each word in the identifier. For example, the following name is unclear and difficult to read:
procedure thisprocedurenamemakesnosense;
This code is quite readable, however:
procedure ThisProcedureNameIsMoreClear;
You might be wondering what all this structure business is and why it's beneficial. You'll find, however, that the Delphi language's structured style of variable declaration lends itself to code that's more readable, maintainable, and less buggy than other languages that rely on convention rather than rule to enforce sanity.
Notice how Delphi enables you to group more than one variable (or formal parameter, for that matter) of the same type together on the same line with the following syntax:
VarName1, VarName2: SomeType; Using this feature tends to make code much more compact and readable compared to a language such as C#, where every variable or parameter must have the type spelled out.
Remember that when you're declaring a variable in Delphi, the variable name precedes the type, and there's a colon between the variables and types. For local variables, the variable initialization is always separate from the variable declaration.
Delphi permits initialization of global variables inside a var block. Here are some examples demonstrating the syntax for doing so:
var
i: Integer = 10;
S: string = 'Hello world';
D: Double = 3.141579;
Note - Preinitialization of variables is only allowed for global variables, not variables that are local to a procedure or function.
Zero Initialization - The CLR sees to it that all variables are automatically zero-initialized. When your application starts or a function is entered, all integer types will hold 0, floating-point types will hold 0.0, objects will be nil, strings will be empty, and so forth. Therefore, it isn't necessary to zero-initialize variables in your source code.
Unlike Win32 versions of Delphi, this is true for variables local to functions as well as global variables.
This chapter is from Delphi for .NET Developer's Guide, by Xavier Pacheco (Sams, 2004, ISBN: 0-672-32443-1). Check it out at your favorite bookstore today.
Buy this book now. |
Next: Constants, Operators >>
More .NET Articles
More By Xavier Pacheco