Statements

From RAD Studio
Jump to: navigation, search

Go Up to Delphi’s Object Pascal Style Guide

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;

If you need to wrap the simple statement, indent the second line two spaces in from the previous line. Here is a compound, or structured, statement:

begin
  B := C;
  A := B;
end;

Compound Statements always end with a semicolon unless they immediately precede an end keyword, in which case the semicolon is optional but recommended by this style guide.

General rules:

  • Always place the begin keyword and the end keyword on their own line
  • Each line should contain at most one statement

Local Variable and Constants Declarations

Local variables should have Camel Caps like all other identifiers. When thinking about naming conventions, consider that one-character field names should be avoided except for temporary and looping variables. Regarding naming local variables, some developers define their own rules like an initial L, which makes sense, but we don’t have a strict recommendation for a local variables prefix.

When a variable is assigned a value, it follows the same rules for assignment statements above, with spaces before and after the := operator.

Constant declarations follow the same rules, except for elements mapped to operating system values that use the OS-defined name (for Windows, often All Caps).

For local variables and constants declared before the begin block, you should use the var keyword at the same indentation of the block that contains it, and the following begin statement on a single line. It will be followed by one or more lines with variable declarations, indented 2 spaces.

While you may declare multiple identifiers of the same type on a single line, this is a discouraged coding style (that also makes version control code differences harder). It is also recommended to use a single space after the colon following the variable name and to avoid aligning variable names vertically. Example:

var
  MyData: Integer;
  MyString: string;

Inline variable (and constant) declarations use a different coding style than variable blocks. For an inline variable, the var keywords are added on the individual declaration line (without a line break), and it is indented like the other statements in the block:

begin
  B := C;
  var K: Integer := B;

We recommend using inline variables for block-local scope declarations (in other words, do not declare in the method var block variables that are used only in one specific block). An example is a for loop local variable, which we recommend declaring using inline variables:

// classic, but now considered incorrect
var
  I: Integer;
begin
  for I := 1 to 10 do
// correct
begin
  for var I: Integer := 1 to 10 do

if statements

If statements should always appear on at least two lines. Do not add extra parentheses around the boolean condition of an if statement. Example:

  // INCORRECT
  if A < B then DoSomething; 
  
  // INCORRECT
  if (A < B) then 
    DoSomething;
  // CORRECT
  if A < B then 
    DoSomething;

In a compound, if statements, put each element separating statements (like begin, else, end) on a new, separate line. In other words, do not place a begin statement immediately following then, but on a new line: For 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;

Some variations are considered valid. One of them uses an if statement on the same line of an else condition, maintaining the original indentation of the external if block (while formally this would be a nested block with further indentation).

   if Condition then
  begin
    DoThis;
  end 
  else if Condition then
  begin
    DoThat;
  end;

If the initial value of a variable is never modified in the code, we recommend using a constant or, in case the value is a result of an expression involving function or method calls, an inline constant with a complex calculation in the assignment.

In if statements, when checking for nil, both of the following expressions have, in general, a very similar effect (with some limited exceptions about method pointers), the Embarcadero libraries code has moved towards using nil checks (if possible), but there isn’t a requirement either way:

if Foo <> nil then
if Assigned(Foo) then

For, While, Repeat Statements

For statements (including the for in variation) should be written on a single line, when possible, with the following begin statement on a new line if a compound statement is needed. For example:

 for i := 0 to 10 do 
  begin
    DoSomething(i); 
    DoSomethingElse;
  end;

For loops with an inline variable declaration for the counter and for in loops use a similar structure:

 for var i: Integer := 0 to 10 do 
    DoSomething(i); 

  for AChar in MyString do 
  begin
    DoSomething(AChar); 
    DoSomethingElse;
  end;

The same is true for while statements, which should have a begin on a separate line following the do keyword. Repeat statements are compound statements by design, so they don’t need a begin end block:

repeat
    x := j;
    j := UpdateValue;
  until j > 25;

Case statements

Case statements should have the initial case of statement on a single line (if it fits the available space) and each condition on a separate line, followed by a semicolon, a space, and a single-line statement. In the case of a compound statement, place the begin on a separate line following the condition and follow regular indentation rules (nested blocks are generally further indented 2 spaces, as shown below so that the case conditions stand out more clearly).

Multiple conditions expressed by ranges or multiple values should be listed on a single line. It is considered acceptable to have them on separate lines as this helps with version control systems and code differencing.

The optional else condition should be followed by a single or compound statement on the following line.

Examples:

  case Control.Align of
    alLeft, alNone: NewRange := Max(NewRange, Position);
    alRight: Inc(AlignMargin, Control.Width);
  end;

  case x of
    csStart:
      begin
        j := UpdateValue;
      end;
    csBegin: x := j;
    csTimeOut:
      begin
        j := x;
        x := UpdateValue;
      end;    
  end;
      
  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;

Exception Handling

Exception handling code should follow the same rules as other statements and blocks. The try-except and try-finally keywords define code blocks requiring standard 2-space indentation and should be terminated by an end keyword with the same indentation of the first keyword.

Except blocks may have one of more on handlers, which should be indented two spaces from the containing except block.

When the except and finally block are combined (see example below), they should be nested following the same standard rules.

Example of correct formatting:

  try
    try
      EnumThreadWindows(CurrentThreadID, @Disable, 0);
      Result := TaskWindowList;
    except
      EnableTaskWindows(TaskWindowList);
      raise;
    end;
  finally
    TaskWindowList := SaveWindowList;
    TaskActiveWindow := SaveActiveWindow;
  end;

  try
    FLength := Value;
    if FLength > Capacity then
      ExpandCapacity;
  except
    on E: EOutOfMemory do
    begin
      FLength := LOldLength;
      raise;
    end;
  end;

Functions and procedures

Global functions and procedures are written with no indentation from the margin. Each function and procedure is placed on a separate line. Function and procedure names follow the general Pascal casing rules for identifiers (the same is true for their parameters names).

There should be no space between the name of the function or procedure and the optional parentheses with the list of parameters and no space after the end of the declaration and the closing semicolon. Each parameter has optional modifiers, the name, a colon followed by a space, and the type. Parameters are separated by a semicolon, with a space after it. In case the parameter has a default value, the = sign should have spaces before and after it.

It is accepted, but not required, to list multiple consecutive parameters of the same type merged together with the names separated by commas and the type specified only at the end:

function CompareStr(const S1, S2: string): Integer; overload;

In case a function or procedure has no parameter is it recommended to omit the empty parentheses both in the declaration and the invocation (unless you need to specifically indicate to the compiler to execute the function or procedure rather than accessing its address).

If possible, a function or procedure declaration should appear on one line. If it doesn't fit, the broken lines are aligned two spaces in from the left. It is not recommended to place each parameter on a separate line.

In case a function or procedure has a declaration and a separate complete definition, while not required by the compiler, is it recommended that the list of parameters is repeated in both locations.

Examples:

function FileExists(const FileName: string; FollowLink: Boolean = True): Boolean;
function FileRead(Handle: THandle; var Buffer; Count: LongWord): Integer; overload;
function Win32Platform: Integer;
procedure AddExitProc(Proc: TProcedure);
function TryStrToTime(const S: string; out Value: TDateTime;
  const AFormatSettings: TFormatSettings): Boolean; overload;

Functions and procedures parameters

Regarding the naming of parameters, some developers define their own rules like an initial A, which stands for “Argument” and is often used in the Delphi libraries source code - but we don’t have a strict recommendation for a parameter name prefix.

As mentioned in the previous section, function and procedure parameters should be named according to the general language rules. Parameters can have modifiers to indicate their behavior. As a general recommendation, you should consider passing as const the parameters of managed types, like strings and interfaces, if they are not modified in the method and they are not passed to unknown functions that might modify them or cause side effects.

We don’t require using const for unmanaged types (including native data types and objects) as there is only limited benefit (in terms of generated code) in doing so. However, given the const modifier improves code correctness and helps a reader understand the code, we recommend its use when applicable. Notice these same rules apply to method parameters.

Assertions

Assertions should be used in library code to test for special logical conditions that must be satisfied, like the prerequisite condition of a parameter or the invariant status of an object. Use assertions when you assume a condition must always be met, regardless of input or condition of executions. Assertions can be a better alternative to an if statement, as they can be disabled in a release configuration build when you assume, they are always met. In an assertion, we recommend adding a string explaining which expected condition is failing.

Do not use assertion to test for conditions that depend on program execution, input, operating system configurations, or anything that is considered a general error condition. Instead, it is recommended to use tests and raise exceptions in any of those scenarios.


Next

Type Declarations