8.0 Statements
This document is not an attempt to define a grammar for the Object
Pascal language. For instance, it is illegal to place a semicolon before
an else statement; the compiler simply won't let you do it. As a result,
I do not lay that rule out in this style guide. This document is meant to
define the proper course of action in places where the language gives you
a choice. I usually remain mute on matters that can only be handled one
way.
The guidelines presented here are based on the public portions of the
Delphi source. The Delphi source should follow these guidelines
precisely. If you find cases where the source varies from these
guidelines, then these guidelines, and not the errant source code, should
be considered your standard. Nevertheless, you should use the source as a
supplement to these guidelines, at least so far as it can help you get a
general feel for how your code should look.
The format of this document and some of its language is based on work
done to define a style standard for the Java language. Java has had no
influence on the rules for formatting Object Pascal source, but documents
found on the Sun web site formed the basis for this document. In
particular the style and format of this document were heavily influenced
by "A Coding Style Guide for Java WorkShop and Java Studio Programming" by
Achut Reddy. That document can be found at the following URL: http://www.sun.com/workshop/java/wp-coding
The Delphi team also contributed heavily to the generation of this
document, and indeed, it would not have been possible to create it without
their help.
Object Pascal source is divided up primarily into units and Delphi
Project files, which both follow the same conventions. A Delphi
Project file has a DPR extension. It is the main source file for a
project. Any units used in the project will have a PAS extension.
Additional files, such as batch files, html files, or DLLs, may play a
role in a project, but this paper only treats the formatting of DPR and
PAS files.
Object Pascal supports long file names. If you are appending several
words to create a single name, then it is best to use capital letters for
each word in the name: MyFile.pas. This is known as InfixCaps, or Camel
Caps. Extensions should be in lower case. For historical reasons, the
Delphi source itself often confines itself to 8:3 naming patterns, but
developers no longer need feel constrained by those limits, even if
turning in source that might be used by the Delphi team.
If you are translating a C/C++ header file, then your Pascal header
translation will usually have the same name as the file you are
translating, except it should have a PAS extension. For instance,
Windows.h would become Windows.pas. If the rules of Pascal grammar
force you to combine multiple header files into a single unit, then use
the name of the base unit into which you are folding the other files.
For instance, if you fold WinBase.h into Windows.h, then call the
resulting file Windows.pas.
All Object Pascal units should contain the following elements in the
following order:
- Copyright/ID block comment
- Unit Name
- Interface section
- Implementation
- A closing end and a period.
At least one blank line should separate each of these elements.
Additional elements can be structured in the order you find most
appropriate, except that the top of the file should always list the
copyright first, the unit name second, then any conditional defines,
compiler directives or include statements, then the uses clause:
{*******************************************************}
{ }
{ Borland Delphi Visual Component Library }
{ }
{ Copyright (c) 1995,98 Inprise Corporation }
{ }
{*******************************************************}
unit Buttons;
{$S-,W-,R-}
{$C PRELOAD}
interface
uses
Windows, Messages, Classes,
Controls, Forms, Graphics,
StdCtrls, ExtCtrls, CommCtrl;
It does not matter if you place a type section before a const section,
or if you mix type and const sections up in any order you choose.
The implementation should list the word implementation first, then
the uses clause, then any include statements or other directives:
implementation
uses
Consts, SysUtils, ActnList,
ImgList;
{$R BUTTONS.RES}
Every source file should start with a block comment containing version
information and a standard copyright notice. The version information
should be in the following format:
{*******************************************************}
{ }
{ Widgets Galore }
{ }
{ Copyright (c) 1995,98 Your Company }
{ }
{*******************************************************}
The copyright notice should contain at least the following line:
Copyright (c) yearlist CopyrightHolder.
If you are a third party creating a file for use by Borland, you
may add your name at the bottom of the copyright notice:
{*******************************************************}
{ }
{ Borland Delphi Visual Component Library }
{ Copyright (c) 1995,99 Borland International }
{ Created by Project JEDI }
{ }
{*******************************************************}
Every source file should contain a unit declaration. The word unit is a
reserved word, so it should be in lower case. The name of the unit should
be in mixed upper and lowercase, and must be the same as the name used by
the operating system's file system. Example:
unit MyUnit;
This unit would be called MyUnit.pas when an entry is placed in the
file system.
Inside units, a uses declaration should begin with the word uses, in
lowercase. Add the names of the units, following the capitalization
conventions used in the declaration found inside the units:
uses
MyUnit;
Each unit must be separated from its neighbor by a comma, and the last
unit should have a semicolon after it:
uses
Windows, SysUtils, Classes, Graphics, Controls, Forms,
TypInfo;
It is correct to start the uses clause on the next line, as in the previous
example, or you may start the list of units on the same line:
uses Windows, SysUtils, Classes, Graphics, Controls, Forms,
TypInfo;
You may format the list of units in your uses clause so that they wrap
just shy of 80 characters, or so that one unit appears on each line.
A class declaration begins with two spaces, followed by an identifier
prefaced by a capital T. Identifiers should begin with a capital letter,
and should have capital letters for each embedded word (InfixCaps). Never
use tab characters in your Object Pascal source. Example:
TMyClass
Follow the identifier with a space, then an equals sign, then the word
class, all in lower case:
TMyClass = class
If you want to specify the ancestor for a class, add a parenthesis,
the name of the ancestor class, and closing parenthesis:
TMyClass = class(TObject)
Scoping directives should be two spaces in from the margin, and
declared in the order shown in this example:
TMyClass = class(TObject)
private
protected
public
published
end;
Data should always be declared only in the private section, and its
identifier should be prefaced by an F. All type declarations should be
four spaces in from the margin:
TMyClass = class(TObject)
private
FMyData: Integer;
function GetData: Integer;
procedure SetData(Value: Integer);
public
published
property MyData: Integer read GetData write SetData;
end;
Interfaces follow the same rules as class
declarations, except you should
omit any scoping directives or private data, and should use the word
interface rather than class.
Except for reserved words and directives, which are in all lowercase,
all Pascal identifiers should use InfixCaps, which means the first letter
should be a capital, and any embedded words in an identifier should be in
caps, as well as any acronym that is embedded:
MyIdentifier
MyFTPClass
The major exception to this rule is in the case of header
translations, which should always follow the conventions used in the
header. For instance, write WM_LBUTTONDOWN, not wm_LButtonDown.
Except in header translations, do not use underscores to separate
words. Class names should be nouns or noun phrases. Interface or
class names depend on the salient purpose of the interface.
GOOD type names:
AddressForm, ArrayIndexOutOfBoundsException
BAD type names:
ManageLayout // verb phrase
delphi_is_new_to_me // underscores
Use InfixCaps, as described at the beginning of this section. See also
the section on unit declarations
Use InfixCaps, as described at the beginning of this section. Begin
each type declaration with a capital T:
TMyType
See also the section on class/interface declarations.
Use InfixCaps, as described at the beginning of this section. Begin
each type declaration with a capital F, and declare all data types in the
private section, using properties or getters and setters to provide public
access. For example, use the name GetSomething to name a function
returning an internal field value and use SetSomething to name a procedure
setting that value.
Do not use all caps for const declarations except where required in
header translations.
Delphi is created in California, so we discourage the use of
notation, except where required in header translations:
CORRECT
FMyString: string;
INCORRECT
lpstrMyString: string;
The exception to the Hungarian notation rule is in enumerated
types.
TBitBtnKind = (bkCustom, bkOK, bkCancel, bkHelp,
bkYes, bkNo, bkClose, bkAbort, bkRetry,
bkIgnore, bkAll);
In this case the letters bk are inserted before each element of
this enumeration. bk stands for ButtonKind.
When thinking about naming conventions, consider that one-character
field names should be avoided except for temporary and looping
variables.
Avoid variable l ("el") because it is hard to distinguish it
from 1 ("one") on some printers and displays.
Method names should use the InfixCaps style. Start with a capital letter,
and capitalize the first letter of any subsequent word in the name, as
well as any letters that are part of an acronym. All other characters in
the name are lower case. Do not use underscores to separate words. Note
that this is identical to the naming convention for non-constant fields;
however it should always be easy to distinguish the two from context.
Method names should be imperative verbs or verb phrases.
Examples:
// GOOD method names:
ShowStatus, DrawCircle, AddLayoutComponent
// BAD method names:
MouseButton // noun phrase; doesn't describe function
drawCircle // starts with lower-case letter
add_layout_component // underscores
// The function of this method is unclear. Does
// it start the server running (better: StartServer),
// or test whether or not it is running
// (better: IsServerRunning)?
ServerRunning // verb phrase, but not imperative
A method to get or set some property of the class should be called
GetProperty or SetProperty respectively, where Property is the name of
the property.
Examples:
GetHeight, SetHeight
A method to test some boolean property of the class should be called
IsVisible, where Visible is the name of the property.
Examples:
IsResizable, IsVisible
Local variables follow the same naming rules as field names, except you
omit the initial F, since this is not a Field of an object. (see section 3.3).
Reserved words and directives should be all lowercase. This can
be a bit confusing at times. For instance types such as Integer are just
identifiers, and appear with a first cap. Strings, however, are declared
with the reserved word string, which should be all lowercase.
All type declarations should begin with the letter T, and should
follow the same capitalization specification laid out in the beginning of this section, or in the section on class declarations.
Blank lines can improve readability by grouping sections of the code
that are logically related. A blank line should also be used in the
following places:
- After the copyright block comment, package declaration, and import section.
- Between class declarations.
- Between method declarations.
Object Pascal is a very clean, easy to read language. In general,
you don't need to add a lot of spaces in your code to break up lines.
The next few sections give you some guidelines to follow when placing
spaces in your code.
- Between a method name and its opening parenthesis.
- Before or after a .(dot) operator.
- Between a unary operator and its operand.
- Between a cast and the expression being cast.
- After an opening parenthesis or before a closing parenthesis.
- After an opening square bracket [ or before a closing square bracket ].
- Before a semicolon.
Examples of correct usage:
function TMyClass.MyFunc(var Value: Integer);
MyPointer := @MyRecord;
MyClass := TMyClass(MyPointer);
MyInteger := MyIntegerArray[5];
Examples of incorrect usage:
function TMyClass.MyFunc( var Value: Integer ) ;
MyPointer := @ MyRecord;
MyClass := TMyClass ( MyPointer ) ;
MyInteger := MyIntegerArray [ 5 ] ;
You should always indent two spaces for all indentation
levels. In other words, the first level of indentation is two spaces,
the second level four spaces, the third level 6 spaces, etc. Never use tab
characters.
There are few exceptions. The reserved words unit, users, type,
interface, implementation, initialization and finalization should always be
flush with the margin. The final end statement at the end of a unit
should be flush with the margin. In the project file, the word program,
and the main begin and end block should all be flush with the margin. The
code inside the begin..end block, should be indented at least two
spaces.
Lines should be limited to 80 columns. Lines longer than 80 columns
should be broken into one or more continuation lines, as needed. All the
continuation lines should be aligned and indented from the first line of
the statement, and indented two characters. Always place begin statements
on their own line.
Examples:
// CORRECT
function CreateWindowEx(dwExStyle: DWORD;
lpClassName: PChar; lpWindowName: PChar;
dwStyle: DWORD; X, Y, nWidth, nHeight: Integer;
hWndParent: HWND; hMenu: HMENU; hInstance: HINST;
lpParam: Pointer): HWND; stdcall;
// CORRECT
if ((X = Y) or (Y = X) or
(Z = P) or (F = J) then
begin
S := J;
end;
Never wrap a line between a parameter and its type, unless it is a comma
separated list, then wrap at least before the last parameter so the type
name follows to the next line. The colon for all variable declarations
contains no whitespace between it and the variable. There should be a
single space following the colon before the type name;
// CORRECT
procedure Foo(Param1: Integer; Param2: Integer);
// INCORRECT
procedure Foo( Param :Integer; Param2:Integer );
A continuation line should never start with a binary operator.[???]
Avoid breaking a line where normally no white space appears, such as
between a method name and its opening parenthesis, or between an array
name and its opening square bracket. If you must break under these
circumstances, then one viable place to begin is after the opening
parenthesis that follows a method name. Never place a begin statement on
the same line with any other code.
Examples:
// INCORRECT
while (LongExpression1 or LongExpression2) do begin
// DoSomething
// DoSomethingElse;
end;
// CORRECT
while (LongExpression1 or LongExpression2) do
begin
// DoSomething
// DoSomethingElse;
end;
// CORRECT
if (LongExpression1) or
(LongExpression2) or
(LongExpression3) then
The Object Pascal language supports two kinds of comments: block, and
single-line comments. Some general guidelines for comment usage
include:
- It is helpful to place comments near the top of unit to explain
its purpose.
- It is helpful to place comments before a class declaration.
- It is helpful to place comments before some method declarations.
- Avoid making obvious comments:
i := i + 1; // Add one to i
- Remember that misleading comments are worse than no comments at all.
- Avoid putting any information into comments that is likely to become
out of date.
- Avoid enclosing comments in boxes drawn with asterisks or other
special typography.
- Temporary comments that are expected to be changed or removed later
should be marked with the special tag "???:" so that they can
easily be found afterwards. Ideally, all temporary comments should have
been removed by the time a program is ready to be shipped.
Example:
// ???: Change this to call Sort when it is fixed
List.MySort;
Object Pascal supports two types of block comments. The most commonly
used block comment is a pair of curly braces: { }. The Delphi team
prefers to keep comments of this type as spare and simple as possible.
For instance, you should avoid using asterisks to create patterns or lines
inside your comments. Instead, make use of white space to break your
comments up, much as you would in a word processing document. The words
in your comments should start on the same line as the first curly brace,
as shown in this excerpt from DsgnIntf.pas:
{ TPropertyEditor
Edits a property of a component, or list of components,
selected into the Object Inspector. The property
editor is created based on the type of the
property being edited as determined by the types
registered by...
etc...
GetXxxValue
Gets the value of the first property in the
Properties property. Calls the appropriate
TProperty GetXxxValue method to retrieve the
value.
SetXxxValue Sets the value of all the properties
in the Properties property. Calls the appropriate
TProperty SetXxxxValue methods to set the value. }
A block comment is always used for the copyright/ID comment at the
beginning of each source file. It is also used to "comment out"
several lines of code.
Block comments used to describe a method should appear before the
method declaration.
Example:
// CORRECT
{ TMyObject.MyMethod
This routine allows you to execute code. }
procedure TMyObject.MyMethod;
begin
end;
// INCORRECT
procedure TMyObject.MyMethod;
{******************************************************
TMyObject.MyMethod
This routine allows you to execute code.
*******************************************************}
begin
end;
A second kind of block comment contains two characters, a parenthesis
and an asterisk: (* *). This is sometimes called starparen comments.
These comments are generally useful only during code development, as their
primary benefit is that they allow nesting of comments, as long as the
nest level is less than 2. Object Pascal doesn't support nesting comments
of the same type within each other, so really there is only one level of
comment nesting: curly inside of starparen, and starparen inside of curly.
As long as you don't nest them, any other standard Pascal comments between
comments of this type will be ignored. As a result, you can use this
syntax to comment out a large chunk of code that is full of mixed code and
comments:
(* procedure TForm1.Button1Click(Sender: TObject);
begin
DoThis; // Start the process
DoThat; // Continue iteration
{ We need a way to report errors here, perhaps using
a try finally block ??? }
CallMoreCode; // Finalize the process
end; *)
In this example, the entire Button1Click method is commented out,
including any of the subcomments found between the procedure's begin..end
pair.
A single-line comment consists of the characters // followed by text.
Include a single space between the // and the comment itself. Place
single line comments at the same indentation level as the code that
follows it. You can group single-line comments to form a larger
comment.
A single-line comment or comment group should always be preceded by a
blank line, unless it is the first line in a block. If the comment
applies to a group of several statements, then the comment or comment
group should also be followed by a blank line. If it applies only to the
next statement (which may be a compound statement), then do not follow it
with a blank line.
Example:
// Open the database
Table1.Open;
Single-line comments can also follow the code they reference. These
comments, sometimes referred to as trailing comments, appear on the same
line as the code they describe. They should have at least one
space-character separating them from the code they reference. If more
than one trailing comment appears in a block of code, they should all be
aligned to the same column.
Example:
if (not IsVisible) then
Exit; // nothing to do
Inc(StrLength); // reserve space for null terminator
Avoid commenting every line of executable code with a trailing comment.
It is usually best to limit the comments inside the begin..end pair of a
method or function to a bare minimum. Longer comments can appear in a
block comment before the method or function declaration.
The body of a class declaration should be organized in the following
order:
- Field declarations
- Method declarations
- Property declarations
The fields, properties and methods in your class should be arranged
alphabetically by name.
Except for code inserted by the IDE, the scoping directives for a
class should be declared in the following order:
- Private declarations
- Protected declarations
- Public declarations
- Published declarations
There are four access levels for class members in Object
Pascal: published, public, protected, and private -- in order of
decreasing accessibility. By default, the access level is published. In
general, a member should be given the lowest access level which is
appropriate for the member. For example, a member which is only accessed
by classes in the same unit should be set to private access.
Also, declaring a lower access level will often give the compiler
increased opportunities for optimization. On the other hand, use of
private makes it difficult to extend the class by sub-classing. If there
is reason to believe the class might be sub-classed in the future, then
members that might be needed by sub-classes should be declared protected
instead of private, and the properties used to access private data should
be given protected status.
You should never allow public access to data. Data should always be
declared in the private section, and any public access should be via
getter and setter methods, or properties.
Methods should be arranged alphabetically. It is correct either to
place your constructors and destructors at the head of this list in the
public section, or to arrange them in alphabetical order within the
public section.
If there is more than one constructor, and if you choose to give them
all the same name, then sort them lexically by formal parameter list, with
constructors having more parameters always coming after those with fewer
parameters. This implies that a constructor with no arguments (if it
exists) is always the first one. For greatest compatibility with
C++Builder, try to make the parameter lists of your constructors unique.
C++ cannot call constructors by name, so the only way to distinguish
between multiple constructors is by parameter list.
If possible, a method declaration should appear on one line.
Examples:
// Broken line is aligned two spaces in from left.
procedure ImageUpdate(Image img, infoflags: Integer,
x: Integer, y: Integer, w: Integer, h: Integer)
Interfaces are declared in a manner that runs parallel to the
declaration for classes:
InterfaceName = interface([Inherited Interface])
InterfaceBody
end;
An interface declaration should be indented two spaces. The
body of the interface is indented by the standard indentation of
four spaces. The closing end statement should also be indented two
characters. There should be a semi-colon following the closing end
statement.
There are no fields in an interface declaration. Properties, however,
are allowed.
All interface methods are inherently public and abstract; do not
explicitly include these keywords in the declaration of an interface
method.
Except as otherwise noted, interface declarations follow the same style
guidelines as classes.
The body of an interface declaration should be organized in the
following order:
- Interface method declarations
- Interface property declarations
The declaration styles of interface properties and methods are
identical to the styles for class properties and methods.
Statements are one or more lines of code followed by a semicolon.
Simple statements have one semicolon, while compound statements have
more than one semicolon and therefore consist of multiple simple
statements.
Here is a simple statement:
A := B;
Here is a compound, or structured, statement:
begin
B := C;
A := B;
end;
A simple statement contains a single semicolon. If you need to wrap
the statement, indent the second line two spaces in from the previous
line:
MyValue :=
MyValue + (SomeVeryLongStatement / OtherLongStatement);
Compound Statements always end with a semicolon, unless they
immediately precede an end statement, in which case the semicolon is
optional.
begin
MyStatement;
MyNextStatement;
MyLastStatement // semicolon optional
end;
Each line should contain at most one statement. For example:
a := b + c; Inc(Count); // INCORRECT
a := b + c; // CORRECT
Inc(Count); // CORRECT
Local variables should have Camel Caps, that is, they should start with
a capital letter, and have capital letters for the beginning of each
embedded word. Do not preface variable names with an F, as that
convention is reserved for Fields in a class declaration:
var
MyData: Integer;
MyString: string;
You may declare multiple identifiers of the same type on a single
line:
var
ArraySize, ArrayCount: Integer;
This practice is discouraged in class declarations. There you should
place each field on a separate line, along with its type.
There should always be a space before the opening bracket "["
and after the closing bracket.
type
TMyArray = array [0..100] of Char;
If statements should always appear on at least two lines.
Example:
// INCORRECT
if A < B then DoSomething;
// CORRECT
if A < B then
DoSomething;
In compound if statements, put each element separating statements
on a new line:
Example:
// INCORRECT
if A < B then begin
DoSomething;
DoSomethingElse;
end else begin
DoThis;
DoThat;
end;
// CORRECT
if A < B then
begin
DoSomething;
DoSomethingElse;
end
else
begin
DoThis;
DoThat;
end;
Here are a few more variations that are considered valid:
// CORRECT
if Condition then
begin
DoThis;
end else
begin
DoThat;
end;
// CORRECT
if Condition then
begin
DoThis;
end
else
DoSomething;
// CORRECT
if Condition then
begin
DoThis;
end else
DoSomething;
One that has fallen out of favor but deserves honorable mention:
if Condition then
DoThis
else DoThat;
Example:
// INCORRECT
for i := 0 to 10 do begin
DoSomething;
DoSomethingElse;
end;
// CORRECT
for i := 0 to 10 do
begin
DoSomething;
DoSomethingElse;
end;
Example:
// INCORRECT
while x < j do begin
DoSomething;
DoSomethingElse;
end;
// CORRECT
while x < j do
begin
DoSomething;
DoSomethingElse;
end;
Example:
// CORRECT
repeat
x := j;
j := UpdateValue;
until j > 25;
Example:
// CORRECT
case Control.Align of
alLeft, alNone: NewRange := Max(NewRange, Position);
alRight: Inc(AlignMargin, Control.Width);
end;
// CORRECT
case x of
csStart:
begin
j := UpdateValue;
end;
csBegin: x := j;
csTimeOut:
begin
j := x;
x := UpdateValue;
end;
end;
// CORRECT
case ScrollCode of
SB_LINEUP, SB_LINEDOWN:
begin
Incr := FIncrement div FLineDiv;
FinalIncr := FIncrement mod FLineDiv;
Count := FLineDiv;
end;
SB_PAGEUP, SB_PAGEDOWN:
begin
Incr := FPageIncrement;
FinalIncr := Incr mod FPageDiv;
Incr := Incr div FPageDiv;
Count := FPageDiv;
end;
else
Count := 0;
Incr := 0;
FinalIncr := 0;
end;
Example:
// Correct
try
try
EnumThreadWindows(CurrentThreadID, @Disable, 0);
Result := TaskWindowList;
except
EnableTaskWindows(TaskWindowList);
raise;
end;
finally
TaskWindowList := SaveWindowList;
TaskActiveWindow := SaveActiveWindow;
end;