Delphi Const
This question has come up in the newsgroups reasonably frequently eventhough there is a help topic all about it filed in the index under theentry “record constants,” so besure to consult the help as well.
Let us begin with an example from the Delphi source code. Consider theUtilWindowClass
variable from theClasses
unit. Delphi uses the variable in implementing theAllocateHWnd
function. Since most of the fields are staticand known in advance, the variable is initialized where it is declared,as shown in Listing 1. Only the hInstance
fieldgets set at run time.
A look at 'array of const' for fun and profit Posted by Allen on Friday, 1 June 2007 in Blogs Back when Delphi was being developed we began to lament the lack of a function that would be able to format a string with format specifiers and some unknown number of parameters. Writeable typed constants (Delphi) Type. Change the const declaration to a var declaration. Old source code that uses writeable typed constants must.
Listing 1
A record variable with initialization from Classes.pas
var
UtilWindowClass: TWndClass = (
style: 0;
lpfnWndProc: @DefWindowProc;
cbClsExtra: 0;
cbWndExtra: 0;
hInstance: 0;
hIcon: 0;
hCursor: 0;
hbrBackground: 0;
lpszMenuName: nil;
lpszClassName: 'TPUtilWindow');
Note that the entire value is wrapped in parentheses, and each fieldname precedes a constant expression. Semicolons separate the pairs ofnames and values.
The fields must occur in the same order in which they appear in therecord type’s declaration. Any field may be omitted, but allsubsequent fields must also be omitted. Any omitted field is initializedwith the default value for itstype.
Arrays of records
To initialize an array constant, the elements’ values need toappear in a comma-separated list within a set of parentheses. Combinethis with the syntax above for record constants to reveal that arrays ofrecords should be initialized with comma-separated lists of parenthesizedsemicolon-separated lists of field: value pairs.
For example, suppose a simple command interpreter has a handfulbuilt-in commands, each implemented with a different function. Theprogram could use a record type to associate a command name with ahandler function and a short description of the command, and shownbelow.
Listing 2
Type declarations for a simple command interpreter
Delphi Constructor
type
TArgArray = array of WideString;
TCommandProcessor = procedure(const Arguments: TArgArray);
TCommand = record
Command: WideString;
Processor: TCommandProcessor;
Description: PResStringRec;
end;
The program could then use an array to keep a list of all the built-infunctions the program recognizes. As with all array constants, the arraymust have constant dimensions; Delphi does not allow dynamic-arrayconstants other than nil
.
Listing 3
An array of built-in commands for a simple command interpreter
// Declarations of command handlers
procedure DoHelp(const Args: TArgArray); forward;
procedure DoExit(const Args: TArgArray); forward;
procedure DoChdir(const Args: TArgArray); forward;
procedure DoHistory(const Args: TArgArray); forward;
resourcestring
// Help messages
RsHelp = 'Print this help message';
RsExit = 'Quit the command interpreter';
RsChdir = 'Change the working directory';
RsHistory = 'Display the command history';
const
{$TYPEDADDRESS OFF}
Builtins: array[0..4] of TCommand = (
(Command: 'help'; Processor: DoHelp; Description: @RsHelp),
(Command: 'exit'; Processor: DoExit; Description: @RsExit),
(Command: 'cd'; Processor: DoChdir; Description: @RsChdir),
(Command: 'chdir'; Processor: DoChdir; Description: @RsChdir),
(Command: 'history'; Processor: DoHistory; Description: @RsHistory)
);
{$TYPEDADDRESS ON}