Copyright (C) 2001-2005 Free Software Foundation, Inc.
Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies.
Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.
Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the copyright holders.
Last updated 2005-01-01.
The GNU Pascal Coding Standards were designed by a group of GNU Pascal project volunteers. The aim of this document is extending the GNU Coding Standards with specific information relating Pascal programming. As a matter of fact, the information contained in the GNU Coding Standards mainly pertains to programs written in the C language. On the other hand, they also explain many of the rules and principles that are useful for writing portable, robust and reliable programs. Most of those general topics could be shared with this document with just a few specific notes, thus cross references are provided which will lead you to the more extensive information contained in the GNU Coding Standards.
This release of the GNU Pascal Coding Standards was last updated 2005-01-01.
The GNU Pascal Coding Standards are available as part of the GPC distribution – in binary distributions as info files, in source distributions also as Texinfo files from which further formats such as HTML, PostScript and PDF can be generated. An HTML version is also available on GPC's home page, http://www.gnu-pascal.de.
Corrections or suggestions for this document should be sent to the GNU Pascal Compiler Documentation mailing list, gpc-doc@gnu.de. If you make a suggestion, please include a suggested new wording for it; our time is limited. A context diff to the “source” Texinfo file would be very appreciated, if at all possible. If you can't provide the context diff, please feel free to mail your suggestion anyway.
These people are the tyrants who are imposing their coding style to the community so far: Peter Gerwinski peter(at)gerwinski.de, Frank Heckenbach frank(at)pascal.gnu.de, Markus Gerwinski markus(at)gerwinski.de, Dominik Freche dominik.freche(at)gmx.net, Nicola Girardi nicola(at)g-n-u.de.
This chapter from the GNU Coding Standards discusses how you can make sure that GNU software avoids legal difficulties, and other related issues. See Intellectual Property (standards).
This chapter discusses some of the issues you should take into account when designing your program.
We support the idea that a variety of programming languages is a good thing and that different languages are appropriate for different kinds of tasks. Unlike the GNU Coding Standards (see Source Language (standards)), we do not try to persuade you to use C, Pascal or any single language for everything.
If you're reading this, you have probably already decided to use Pascal for some project or are considering using it. This documentation will suggest you how to format your Pascal code when you do so.
You can link a C library or C object code to your Pascal program or unit. Please note the description in the GPC manual on how to do so (see Other Languages (gpc)).
In particular, to access C libraries, we strongly recommend using C wrappers. This is a portability issue. There might be changes in different versions of the library which might affect direct external declarations in Pascal code. You should update the wrappers so that Pascal programs or units work with whatever version of the library you have.
There are times when you deal with large packages and you can't easily retain compatibility to different versions of the packages themselves. In this case, you can link directly to the library you're going to work with, and link a supplementary C file which does nothing but the version check. This is an example:
#include <foo.h> #if FOO_MAJOR != 1 || FOO_MINOR != 2 #error The GPC interface for libfoo was only written for libfoo-1.2. #error Please get libfoo-1.2 or check for a version of the GPC interface #error matching your version of libfoo. #endif
Note the use of != instead of < or >, to perform a very strict version check. Please keep in mind that this is alright if there is only one implementation of a library, i.e., you can do this with GTK, but you can't with libc, libm, curses etc.
An automatic header translator is planned which would make the C wrappers superfluous. This is a highly non-trivial job and it's not sure that it's at all possible, so it will at least take some time to be available.
You can assume the GNU C Compiler is used to compile the wrappers and, in general, any C code snippet you link to your Pascal code. The reason for such an assumption is that only GNU C Compiler is guaranteed to have all conventions compatible to GNU Pascal Compiler on every platform they run on, as they share the same backend. Also, The GNU Pascal Compiler is always built together with the GNU C Compiler, so gcc can be assumed to be available wherever gpc is.
Many GNU Pascal facilities are provided which extend the standard Pascal language. Whether to use these extensions in implementing your program is a tedious question.
On the one hand, using the extensions can make a cleaner program. On the other hand, people will not be able to build the program unless the GNU Pascal Compiler is available. This might cause the program not to compile with other compilers.
In general, it is best to retain compatibility to other compilers or to the language standards, if this compatibility is easy to achieve. In general, sadly enough, to achieve compatibility you get considerable drawbacks. For example, you might have to add lots of {$ifdef}s to cater for some non-standard compilers, which make the code harder to read, write, test and maintain. Moreover, {$ifdef}s themselves are non-standard extensions, so you don't win much this way.
In the end, we suggest not to bother too much about compatibility. All of the GNU Pascal Compiler interfaces (compiler and Run Time System) are open. This means they can be implemented for other compilers when needed or even the same sources can be used provided the license is preserved (read more about the GNU General Public License at http://www.gnu.org/copyleft/gpl.html), rather than crippling the code by not using the extended features. A (limited) example of this strategy is in the gpc-bp unit for Borland Pascal, distributed with the GNU Pascal Compiler. You might want to look at its interface to see what exactly it contains. It's easy to extend it by more compatibility features when needed, though there are features that cannot easily be emulated (in particular those that have a special syntax).
Please do not use the following features, especially the ones that were implemented just for backward compatibility:
Str (Foo, s); s := 'Hello ' + s;
FillChar (s, SizeOf (s), 0);
to clear a string, is wrong in GNU Pascal and inefficient even in Borland Pascal, since the following could be used:
s := '';
This would only clear the length field of the string s.
The GNU Coding Standards have nice statements on this topic. See Using Extensions (standards).
This chapter from the GNU Coding Standards describes conventions for writing robust software. It also describes general standards for error messages, the command line interface, and how libraries should behave. We encourage you to read that part of the GNU Coding Standards. See Program Behavior (standards).
Here are special notes for Pascal programming, anyway.
The choice between signal functions, discussed in the GNU Coding Standards, is done in the Run Time System so you needn't care about it.
Another discrepancy with the GNU Coding Standards is the default behavior for error checks that detect “impossible” conditions. We don't suggest just aborting. This implies that every user can be a programmer, but we don't believe this is realistic. Our advice is to print a reasonable error message so that users can report bug descriptions to programmers who didn't notice the bug themselves or could not reproduce it.
Also, the GNU Coding Standards suggest checking every system call for an error return. That applies to C. In Pascal, error checking is often automatic, thus you needn't bother with error checking. Many I/O routines don't return a value (for example, Reset), but those that do should usually be checked.
Of course you can disable automatic error checks and see to them for yourself. In fact, some errors might cause the program to automatically abort with an error message. Instead, especially in units or modules, you might want to report errors and give the user a chance to intervene and fix things up. To do so, you must use the {$I-} compiler directive, and check the value of IOResult (see IOResult (gpc)) or the global error variables such as InOutRes (see InOutRes (gpc)). Note that I/O routines return immediately if InOutRes is set, so it's not necessary to check it after each operation, so the following is possible:
{$local I-} Rewrite (f, 'bla'); WriteLn (f, 'foo'); WriteLn (f, 'bar'); WriteLn (f, 'baz'); Close (f); {$endlocal} if InOutRes <> 0 then begin WriteLn (StdErr, GetIOErrorMessage); ... end;
However in your code you might want to also check Rewrite and other opening calls, which are the most likely to fail, and you will avoid unnecessary further calls.
There is a set of routines in the GPC unit for naming temporary files, configuration files and many other file name related stuff. The advantages of using these are that they work for different kinds of systems (for example Unix and DOS), and that future problems can be corrected in one place in the Run Time System rather than in several different programs or units.
As far as libraries are concerned, we suggest that you don't put each routine in a separate file. Hopefully someday the GNU Pascal Compiler will do this automatically on the linker level. At the moment, we believe that the convenience to the programmer is much more important than binary size. We also recommend not using a name prefix, as name conflicts can be resolved by qualified identifiers (UnitName.RoutineName).
This chapter provides advice on how best to use the Pascal language when writing software. Of course, the rules apply to published code only – if you for example want to comment things out with old style comments like (* this one *), you should do it temporarily and remove it before distributing your code. But since you never know if and when you are going to publish your code, it's a good idea to stick to the rules from the beginning.
Pascal code file names should have the .pas suffix. The file name without the suffix should usually correspond to the name of the program/unit/module, but all in lower case. There should be only one program/unit/module in a file.
Code must compile with the -Wall flag, with and without the -O3 flag with no warnings. (See Compiler Directives, for how to intentionally disable certain warnings if really necessary.)
Don't use the automatic Result variable in functions. If you want one, just declare it:
function Foo (...) = Bar: Integer;
Use the declaration with =, not without it, unless you want to be strictly PXSC compatible.
If a function returns a Boolean to indicate success, True should mean success and False failure, unlike some C routines where 0 means success.
Avoid goto and similar statements, like Exit, Return, Break, Continue. Avoid goto at any price (except possibly a non-local goto to return from deeply nested, recursive functions in case of error). Avoid the others if this is possible with reasonable effort. If it would require an additional Boolean variable, this counts as an excuse for using those statements if you really want. Note that often, code becomes significantly simpler by not using Break etc. and instead using a better loop condition or a different kind of loop.
Never modify for loop counters, or rely on their value after the loop. (Well, that's not merely a coding style, that's the definition of Pascal. Doing such things will produce undefined results.)
Never rely on undefined behavior. For example, that global variables seem to be initialized to 0 at the start of the program, or perhaps sometimes newly allocated memory seems to be initialized, or memory after deallocation still seems to hold some values, or that for loop counters seem to have a certain value after the loop – none of these is guaranteed, and the behaviour may change when you change compiler or its version, or when you change platform. Undefined means undefined, and the fact that such things might seem to work on all systems you have checked and with 42 other compilers means exactly nothing.
In comparisons put the “more variable” expression on the left side:
for i := 1 to 10 do if a[i] = Foo then for j := 1 to 10 do if b[j] = a[i] then ...
Considering the second line of the above example, the expression on
the left (a[i]
) varies each turn, but the right side
(Foo
) does not. (In this case we assume that Foo
is a
constant or a function which doesn't depend on i
or some
other global data. Otherwise it might make sense to put Foo
on the left, and perhaps use an extra comment to point this out.)
The last line of the above example might look strange, because
b[j]
and a[i]
might look as though they have the same
level of “variableness”. But in fact, j
ranges more often
than i
, i.e. each time i
changes, j
has already
changed 10 times.
Avoid code duplication. It is easy to copy the code, but it becomes a maintenance nightmare to change several similar places. Use routines or subroutines, units or modules, whatever. Plan each part of the code so that it can be extended. Don't pull too clever tricks in places that will likely be changed later.
Do not surround single statements with begin and end, unless you have to avoid the dangling else problem or the single line statement forms a whole routine body! See the following examples:
if foo then begin if bar then baz end { Avoid the dangling else problem. } else qux { Single line statement. }
Do not write empty unit initializers. This is what not to do:
... procedure Foo; begin ... end; begin end.
Instead, simply:
... procedure Foo; begin ... end; end.
Do not write unused declarations, unless in interfaces which are meant to be used by the importer.
Remember that Booleans are Booleans. Please use if Foo then instead of if Foo = True then, and if not Foo then instead of if Foo = False then. Also, use until False in place of until 1 = 0 – this looks smarter. Another common situation is Foo := Expression instead of if Expression then Foo := True else Foo := False.
Avoid duplicate global identifiers, i.e. don't overload a built-in identifier, although the GNU Pascal Compiler allows this, and don't use the same global identifier in several units or modules. (Thanks to “qualified identifiers” such identifiers pose no problem to the compiler but still can confuse humans.)
We discourage the use of global variables for non-global purposes
(e.g., the use of a variable Counter
used as a counter in
various local routines). Declare a counter variable for each routine
that needs it, instead. In general, this also allows for better
optimization of the code generated.
When you need an infinite loop (which may be left with
Break), we suggest you use a repeat
rather than a
while
loop because it shifts your code less to the right (at
least, if there's more than one statement in the loop). That is:
repeat ... until False
Instead of:
while True do begin ... end
As stated in the GNU C library documentation (see Consistency Checking (libc)), when you're writing a program, it's often a good idea to put in checks for violations of basic assumptions. Consider the following procedure in Pascal:
procedure DoSomethingOnAPString (StrPtr: PString);
You may implicitly assume that the above procedure will never be
called with nil
as its argument, but it is safer to check for
the “impossible condition”, i.e. check that StrPtr is other
than nil
, like this:
procedure DoSomethingOnAPString (StrPtr: PString); begin Assert (StrPtr <> nil); ... end;
When this check fails, the program produces a runtime error. You then may infer that the code which calls this procedure is buggy (or that you need to extend this particular routine), so this may indeed be helpful in locating the problem. In other words, checking for basic assumptions at the beginning of a routine body or other strategic places is the right way to make sure a function isn't being misused.
The GNU C library provides the assert
macro for this kind of
checks. GNU Pascal provides a Pascal counterpart which is called
Assert
, which behaves a little differently. Assert
won't abort your program, but rather cause a runtime error
(see Assert (gpc)) which, e.g., you can catch using the
Trap unit (see Trap (gpc)).
Once you think your program is debugged, you can disable the error
checks performed by the Assert
routine by recompiling with
the --no-assertions switch. No change to the source code is
needed in order to disable these checks. Side-effects in the
argument to Assert are still evaluated (unlike in C), so it
is alright to write:
Assert (MyFunction (Foo, Bar) > 0)
This will always call MyFunction
, but only make sure that its
result is positive if --no-assertions is not given.
However, it is recommended that you don't disable the consistency checks unless you can't bear the program to run a little slower.
First of all, avoid unnecessary spaces at the end of the lines. Also remember not to save the file with TAB characters, as different editors or different configurations will interpret them with a different amount of spaces, thus breaking indentations. (If you use GNU Emacs, the untabify function comes in handy; if you use VIM, the option expandtab (:set et); in PENG, the option Expand tabs can be used.)
Please avoid the use of any control characters, except newline, of course. This means no form feed characters (#12), i.e. new page characters. They are recommended in the GNU Coding Standards to separate logical parts of a file, but don't use them at least in Pascal code. No SUB character (#26) either, misused as an end-of-file indicator by DOS. Older DOS editors put that character at the end of each file for no good reason, though even the FAT file system knows about the end of a file by its own.
We recommend a maximum line length of 68 characters, so that it can be printed in TeX with default font on A4, or 78 characters, for 80-column wide screens. This is not a fixed rule because breaking lines too often decreases readability of source code.
Use empty lines between blocks. Blocks are long comments, type, const, var, label sections, routine bodies, unit/module initializers/finalizers, program, unit, interface, implementation, module, export, uses, import lines, global compiler directives. As far as long comments that refer to the following declaration, put only an empty line before the comment, not between the comment and the declaration itself. A special exception is between blocks within the same routine – do not use empty lines there. For example:
procedure Short; var Foo: Integer; Bar: Char; begin ... end;
But remember to use empty lines to separate subroutines, like the following:
procedure Long; const ... var variables used by Sub ... procedure Sub; var ... begin ... end; var variables not used by Sub ... begin ... end;
Note that you shouldn't put an empty line after the main routine declaration, unless a subroutine declaration immediately follows. Otherwise the main routine declaration would look like a forward declaration.
Notice that in the code snippet above we separated local variables (or constants) before and after the subroutine – this is not mandatory.
Of course, what we said for subroutines is also valid for sub-subroutines at any depth.
An empty line should be put between declarations of the same type, where appropriate, to separate them logically. In case there is a comment before the declaration, the empty line must be before the comment. Otherwise, the empty line goes before the declaration.
Empty lines can be used in long comments to separate paragraphs.
No empty lines at the beginning or ending of a file, only one newline at the ending. No multiple empty lines.
The comments should be placed in braces like this:
{ This is a nice comment. }
Do not use the old style comment between brackets and asterisks, like this:
(* This is an ugly comment. One you mustn't write. *)
Also, do not use comments introduced by the double slash:
// Another kind of comment not to write.
Although ISO Pascal explicitly allows for mixed comments, the GNU Pascal Compiler doesn't even accept it unless you turn it on the option with the appropriate compiler directive {$mixed-comments} – but you don't want to do it. Here are a couple of examples of mixed comments, which you should not follow:
(* This ... } { ... and that. *)
Also, try to avoid nested comments, like { { This one } }. These are alright if you want to put some TeX in a comment or something more exotic. Whatever reason you have to use nested comments, you need to turn on the option with the appropriate compiler switch, which is {$nested-comments}. Do not use the --nested-comments command line option. Put all such options in the source, so that someone else trying to compile it doesn't have to figure out what command line switches are needed, and because command line options would affect all source files, e.g. when compiling a project with multiple units/modules.
Please write the comments in your program in English, because English is the one language that nearly all programmers in all countries can read. If you do not write English well, please write comments in English as well as you can, then ask other people to help rewrite them. If you can't write comments in English, please find someone to work with you and translate your comments into English.
You should adopt “French Spacing”, i.e. only one space at the end of a sentence. This way, you can't use GNU Emacs M-a and M-e key combination to move through sentences. We hope that you can live without that. Also, please put just one space after the comment opening brace and before the closing brace.
If a comment regards only one line of code, possibly write it after the line of code, in the same line, separated from the code with two spaces. This is also allowed for the interface section of a unit and for global variables. Most often you are likely to write this sort of comment beside record/object fields. In other cases, comments go in one or more lines of their own, like this:
{ foo bar baz }
Or longer:
{ foo bar baz }
Or with paragraphs:
{ foo bar baz qux }
The comments need to be placed before the code they describe, and they need to get the same indentation level. This example should make this clear:
{ My types. } type ... type { My first types. } Foo = Integer; ... begin { My first statement. } Bla; { Start of loop. } repeat { Body of loop. } ... { Finish when Something happens. } until Something end;
Note the position for the comment to until.
Comments describing a global declaration should be on one or more lines of their own, immediately before the declaration. For example:
{ This is Foo. It does this and that. } procedure Foo;
Do not write “trivial” comments, like the ones listed in the examples above. You should avoid comments by writing clear code. Linus Torvalds points this out strongly in the Kernel Coding Style:
Comments are good, but there is also a danger of over-commenting. Never try to explain how your code works in a comment: it's much better to write the code so that the working is obvious, and it's a waste of time to explain badly written code. Generally, you want your comments to tell what your code does, not how.
(Note that we otherwise deviate quite a bit from Linus's coding style.)
“Tricky” code is worth being commented. We define “tricky” the code that does non-obvious things, relies on non-obvious assumptions, has non-obvious implications, there is anything to note when changing it, is not what it looks at first sight, there is a side effect, or requires other parts of the source file to be changed simultaneously with it. Tricky code should be used very sparingly.
In the case that a comment refers to some other place in the code, either in the same file or in a different file, please refer to it not by line number (this will change too often) but by routine name or context. Also, think whether it is useful to put a comment in the other place pointing back. (Not always, but sometimes this has proved useful to us.)
To comment out parts of code that should not be compiled, you need to surround it with {$if False} ... {$endif} rather than using a comment.
To separate logical parts within big modules or units, you can use a special comment – we suggest this fixed pattern as it's easily searchable:
{@section Name of the section} {@subsection Name of the subsection}
Note that no space follows the opening brace nor predeces the closing brace in this case.
A module or unit or library should have a comment for each of its interface declarations, so that the interface part of the source file is a reliable source of documentation. This is optional for any declarations introduced only in the implementation section or in programs. Of course, several related declarations (e.g., groups of constants) can share a comment.
A utility called pas2texi will be written to build Texinfo files from Pascal comments. This will allow certain kinds of markup within comments. They will be described in the documentation of pas2texi and/or in future versions of this document.
You can use “fixme” comments, to point out things to be fixed in the code, or in a library (or module, or unit, or compiler used) which directly affect the code, requiring a work-around. These comments are prepended by at least two @ – add as many @ as the urgency of the issue increases.
These comments may contain more or less obscure details about the problem, especially if the root of the problem is elsewhere. For example, the comment { @@fjf226 } declares the following code a work-around to a GNU Pascal Compiler problem which is demonstrated by the GNU Pascal Compiler test program fjf226.pas. (It is a file you can find in the GNU Pascal Compiler source package.)
“Fixme” comments should not be mixed with ordinary comments. If you need both kinds, use them separately, even if directly after each other. They can be used everywhere, even within statements, since they are temporary in nature. Most normally they happen to fall in the body, unless they influence interfaces. In particular, interfaces that are likely to be changed should have a @@ comment immediately before their description comment.
Please start each file with a comment containing, in this order:
In general, you should follow this order for declaration blocks:
You may deviate from this order when it is necessary or makes the code more readable. This is an example where the order can't be respected:
type TSomething = record This, That: Integer end; const SomeConst = SizeOf (TSomething);
The rules above apply to declaration blocks within routines, too.
When there are several, more or less independent parts, especially in a large unit or module, you may apply this order within each part. Do not put, for example, constants of all parts together. You have to keep the code readable.
Variables that are used only in the main program must be declared globally in Pascal, although GNU Pascal offers an extension for declaring variables at arbitrary places in the code (see var (gpc)). In this case, in contrast to the previous general rule, it is often better to put their declaration just before the main program's begin, after all routines etc., especially when there are more than a few such variables and the size of the source file is not small. Thus, the variable declaration block is easier to see and change for the programmer when editing the main program, and you make sure that routines don't use them accidentally.
When you declare a type together with its pointer type, declare the pointer first. It is easier to recognize especially if the type is a long record or object. Also, it makes possible using recursive structures (i.e., using pointers to a type within this type). You should prepend a T to the type name and a P to the associated pointer type. See the example:
type PMyInt = ^TMyInt; TMyInt = Integer; PStrList = ^TStrList; TStrList = record Next: PStrList; s: TString end;
Note that the Next field is specified first. We suggest always putting it as the first field in recursive types, as it allows some generic list routines and may be a little more efficient to walk the list, i.e. no offsets.
We suggest putting all pointer types within each type declaration first, although we don't consider this mandatory. This is an example:
type { Pointer types } PFoo = ^TFoo; PBar = ^TBar; PBaz = ^TBaz; { Some custom integer types } TFoo = Integer attribute (Size = 16); TBar = Cardinal attribute (Size = 16); TBaz = Cardinal attribute (Size = 32);
Within object types you can have three declaration areas. There are three reserved words for introducing these areas: public, protected, private. Within each of these areas follow this order:
In the object implementation part, put the routine bodies in the same order in which they appear in the declaration in the interface. This also applies to units and modules, in which the implementation should reflect the interface declarations.
Do not use the trailing ; at the end of a block, i.e. before end, until, etc. except case – the last branch before the else branch (or the last branch if there is no else branch) should have a ;, to avoid problems like:
case ... Foo: if Bar then { later inserted } begin ... end { if there's no semicolon here ... } else { ... this will be mistaken as the then's else } ...
(Same if the if was there for longer and the else branch of the case is later inserted.)
In an object, it may look strange to omit the ; after the last item which is most often a method. Therefore we allow it, and for consistency also in records.
Reserved words should be all lower case, including directives, i.e. words that are reserved only in some contexts, like protected. If you use directives as identifiers (which is likely to cause you pain) outside of their contexts, write them like identifiers.
As a special exception, you can use capitalized File when used as a type of its own, i.e. an untyped file, unlike file of Char. The same can't be said for procedure as a type (Borland Pascal style) since File can be a proper type, while procedure is a type constructor, i.e.:
procedure Foo (var a: File); { This works. } procedure Foo (var a: procedure); { This doesn't. }
Next issue is capitalization of identifiers. There's no difference between built-in and user-defined identifiers. Only the first letter should be capital, or, if there are concatenated words or acronyms, the first letter of each word should be capital – do not use underscores. Acronyms that have become part of the natural language can be written like that. For example, Dos or DOS; but always GPC, not Gpc. Here are some examples of identifiers: Copy, Reset, SubStr, BlockRead, IOResult, WriteLn, Sqr, SqRt, EOF, EOLn.
These rules apply to constants identifiers, too, unlike C macros.
Also note that very small identifiers can be written lower case, like i or s1 or xx. Such short identifiers should be used only locally. They can be used for parameters of global routines, because the scope of such parameters is local as well, and their names in fact don't matter at all to the caller. The use of such identifiers in a global context should be avoided, especially in units or modules or libraries (because the author doesn't know in which contexts they will be used).
Please be consistent with your capitalization. You know that Pascal will not hurt you if you change capitalization for an identifier throughout the code, but please stick to the same capitalization.
For identifiers for the values of enumeration types and for blocks of constants, i.e. places where you introduce a lot of identifiers, it can be useful to use a two-letter lower-case prefix and _, in contrast to the previous rules:
type TFooBar = (fb_Foo, fb_Bar, fb_Baz, fb_Qux);
{ My Foos } const mf_Foo = 1; mf_Bar = 3; mf_Baz = 42;
In object oriented code (especially in constructors), there is often the need to have a parameter correspond to an object field (e.g., to pass a value with which to initialize the field). Since both can't be called the same, the field should have the “natural” name since it's usually used in more routines, and the parameter name should be “mangled”. FIXME: We haven't found a really satisfactory rule for mangling yet (some use a as a prefix), and if you have any good idea, let us know.
As far as macros are concerned, we strongly recommend that you do not use them. Please, do not use macros in your programs. Try to avoid using macros in your programs, because they are evil. We believe you must not use macros in your code. Said that, if you still dare to use a macro, write it capitalized entirely and separate words with underscores. Since macros do not follow Pascal's scoping, it makes sense to write them differently. This applies to conditionals, too.
We generally suggest using as few compiler directives as reasonably possible, because they make the code harder to understand (e.g., when checking for side-effects) and to modify (e.g., when moving parts of code into or out of the scope of compiler directives). The directives should be invoked like in the example:
{$your-compiler-directive}
Definitely not this way (see Comments):
(*$do-not-use-such-a-compiler-directive*)
Also, definitely not this way, which is dependent on line breaks, unlike Pascal normally is:
#your-compiler-directive
Same goes for macro definitions:
{$define ...}
This also saves the ending backslash before line breaks, in contrast to #define. But you will not use macros, will you? (see Capitalization)
As far as spacing is concerned, don't type a space before the closing brace, as there can't be one after the opening brace. If you concatenate many directives together, don't put a space between each of them, a single comma is enough.
No comments should be inserted within the directives. Write them separately, instead, like this:
{$X+} { We need extended syntax. }
Borland Pascal allows mixing comments with directives, but it's really a misuse.
Short forms for calling the directives are alright, but long forms are at least as good, not to say preferred. Short forms must be written in caps, while long forms in lower case (except for case-sensitive arguments like messages and file names – of course, file names must always be treated as case-sensitive, even on DOS, to preserve code portability).
You can combine several directives, also mixing short and long ones, in a single call, for example like the following:
{$gnu-pascal,I-,X+}
Any unit or module should have {$gnu-pascal,I-} or {$gnu-pascal,I+} near the beginning (after the head comment with description and license). {$gnu-pascal} lets the unit be compiled without dialect options even if the main program is compiled with some. {$I-} or {$I+} indicates to the user (even though one of them is the default) whether the unit handles/returns input/output errors or lets them cause runtime errors. The former is preferable for most units. For programs, this item is optional. Routines that return input/output errors should have the attribute iocritical (see attribute (gpc)):
procedure CriticalRoutine; attribute (iocritical);
{$W-} (no warnings) must only be used locally and must have a “fixme” comment (see Comments) because it indicates a problem with the code or the compiler.
Please, don't disable warnings when you're just too lazy to write the code that does not produce warnings.
Any compiler flags that are not set globally (for example, together with {$gnu-pascal}, see above) should be set with {$local ...}. In other words, not this way:
{$I-} Reset (f); {$I+}
But this way:
{$local I-} Reset (f); {$endlocal}
The former is wrong if {$I-} was set already. Even if a programmer might know and take into account which is the global setting, this might be changed sometime, or part of the code may be copied or moved. The latter form is safer in these cases.
To make it even clearer, from the last two rules it follows:
{$local W-} Foo; {$endlocal} { @ GPC produces a superfluous warning }
Again, try to avoid local directives. {$I-} is sometimes needed. {$X+} might be used if really, really necessary (as locally as possible): avoid pointer arithmetics.
Don't use {$X+} to ignore function results, don't use {$ignore-function-results}, either. It is too easy to ignore a result one should not ignore. Sometimes, especially when linking to a foreign C library, you might have to deal with functions which have a superfluous result, which you probably don't want to check. You can declare such functions with the ignorable attribute, so that their results are silently ignored.
Also use dummy variables if you want to ignore the result of a particular call to a function whose result should in general not be ignored. But in such cases check carefully whether the result can really be ignored safely. If, however, an unexpected result would indicate an “impossible” situation, it's usually better to check the result and print a warning or abort in the unexpected case, at least if DEBUG is defined (see Compiler Directives).
Linker directives, i.e. {$L} for libraries and C (or other language) source files should be put near the start in programs and shortly after the implementation line in units or modules. Several libraries and C source files in one directive are possible when they belong logically together (for example, a library and its C wrappers), but not for separate things. This directive should not be mixed with other directives (which doesn't even work if L comes first – the other way around it might work, but shouldn't be used). The external declaration of the library or C routines should immediately follow the directive (except in a unit or module for those that go in the interface). Using {$L} in programs is often not a good idea, making a unit is often better for abstraction and reuse.
Conditional compilation might be useful sometimes, but you should use as few {$ifdef}'s as possible, as they decrease readability. When conditionals are used for differences between systems, check for features (for example, __BYTES_LITTLE_ENDIAN__) or groups of systems (for example, __OS_DOS__) rather than individual systems, to better cater for systems you don't know or that may not even exist yet.
If possible (this might not be available), use the predefined constants (for example, BytesBigEndian, OSDosFlag) rather than defines – for code that is possible (the “always false” branch will be optimized away, but you still get its syntax checked as an additional benefit besides not using the preprocessor); for type declarations it is usually not possible and you have to use the defines. A good example is the declaration of TWindowXY in the CRT unit. See:
TWindowXYInternalCard8 = Cardinal attribute (Size = 8); TWindowXYInternalFill = Integer attribute (Size = BitSizeOf (Word) - 16); TWindowXY = packed record {$ifdef __BYTES_BIG_ENDIAN__} Fill: TWindowXYInternalFill; y, x: TWindowXYInternalCard8 {$elif defined (__BYTES_LITTLE_ENDIAN__)} x, y: TWindowXYInternalCard8; Fill: TWindowXYInternalFill {$else} {$error Endianness is not defined!} {$endif} end;
The DEBUG flag should be used for (and only for) code to help debugging, i.e. code which doesn't change the real functionality. Programs must compile with and without setting DEBUG. The latter may run slower and may produce useful additional messages in a suitable form, i.e. clearly marked as debug messages, for example prefixed with DEBUG: , and may abort when it detects erroneous or dubious conditions.
Conditionals can also be used to make different versions of some code, for example, using GMP numbers if a condition is satisfied and using normal integers or reals otherwise (GMP is a library for working with arbitrarily large numbers). In this case, the name and meaning of all such defines used in a file must be explained in a comment near the top. (For examples, see the __BP_TYPE_SIZES__, __BP_RANDOM__ and __BP_PARAMSTR_0__ in the System unit.) The code must compile with any combination of those conditionals set, which means you have to test exponentially many cases – here is a good reason to keep their number as small as possible.
Another similar use of conditionals is to select between different implementations. You should adopt this strategy only if all of the implementations are really supported or planned to be supported. Otherwise, you'd better move the old implementations into your “museum” and keep the code clean. The notes about code compilation of the previous rule apply here as well.
When you need to deal with complicated conditionals use Pascal syntax, i.e. format the conditionals according to the rules for Pascal code, rather than C syntax. This is a silly example:
{$if defined (Foo) or False}
Instead, this is an example not to follow:
{$if defined (Foo) || 0}
Or even worse:
#if defined (Foo) || 0
A special conditional can be used to comment out code temporarily. Here's the appropriate syntax:
{$if False} ... {$endif}
A standard conditional statement should be used in programs or units or modules you distribute to make sure that the appropriate version of the GNU Pascal Compiler is used. You can follow this template:
{$if __GPC_RELEASE__ < 20020510} {$error This unit requires GPC release 20020510 or newer.} {$endif}
In general, no multiple spaces should be used except for indentation and as indicated below.
A single space goes before and after operators, and := and .. as well as : in Write, WriteLn and WriteStr; after the comma and other :. This example ought to make it clearer:
var Foo: Integer; ... begin Foo := 42; WriteLn (Foo + 3 : 5, ' bar') end;
No space should go before unary -. In fact, these are the correct forms: x - 1, -x, -1.
A space must go before the opening parenthesis (() and after the closing parenthesis ()), unless adjacent to further parentheses, brackets, ^, ;, ,. In other words, a space goes between identifiers or keywords and the opening brace ((). (All the other spaces in this example are implied by the previous rule already.) See:
Foo (Bar^(Baz[Qux * (i + 2)]), Fred (i) + 3);
For indexing arrays actually don't use a space before the opening bracket, i.e. Foo[42] rather than Foo [42]. However, insert a space before the opening bracket in array declarations, like:
Foo: array [1 .. 42] of Integer;
A space goes before the opening bracket of a set constructor in some situations – those brackets should be treated like parentheses, unlike the brackets used in array indexing. For example:
x := [0, 2 .. n];
But:
Foo ([1, 2, 3]);
No spaces for . and ^:
Rec.List^.Next^.Field := Foo
As we already pointed out, a single space goes after the opening brace and before the closing brace in comments, but not in compiler directives. Also, and we said this already too somewhere in the manual, two spaces go before comments after a line of code. For example:
Inc (x); { Increment x. }
Optionally use additional spaces to make “tabular” code. In our opinion, this increases readability a lot because the human eye and brain is trained to recognize such structures, and similiarities and differences between the lines can be easier seen, and when changing the code, it's easier to find related places. An application of this principle can be seen in interface declarations (not so much applicable when separated by comments, but, for example, when described by a shared comment above them all):
function Pos (const SubString, s: String): Integer; function LastPos (const SubString, s: String): Integer; function PosCase (const SubString, s: String): Integer; function LastPosCase (const SubString, s: String): Integer; function CharPos (const Chars: CharSet; const s: String): Integer; function LastCharPos (const Chars: CharSet; const s: String): Integer; function PosFrom (const SubString, s: String; From: Integer): Integer; function LastPosTill (const SubString, s: String; Till: Integer): Integer; function PosFromCase (const SubString, s: String; From: Integer): Integer; function LastPosTillCase (const SubString, s: String; Till: Integer): Integer;
Also possible:
procedure Foo; function Bar ...; procedure Baz;
And, of course:
const FooBar = 1; Baz = 2; Quux = 3;
The same “tabular” strategy used in interfaces and const declarations can be used in initializers:
const Foo: TBarArray = (('Foo' , 3), ('Bar baz', 42), ('' , -1));
And in case statements:
case ReadKeyWord of kbLeft : if s[n] > l then Dec (s[n]) else s[n] := m[n]; kbRight : if s[n] < m[n] then Inc (s[n]) else s[n] := l; kbUp : if n > 1 then Dec (n) else n := 5; kbDown : if n < 5 then Inc (n) else n := 1; kbHome : s[n] := l; kbEnd : s[n] := m[n]; kbPgUp, kbCtrlPgUp: n := 1; kbPgDn, kbCtrlPgDn: n := 5; kbCR : Done := True; end
And optionally in other code:
WriteCharAt (1, 1, 1, Frame[1], TextAttr); WriteCharAt (2, 1, w - 2, Frame[2], TextAttr); WriteCharAt (w, 1, 1, Frame[3], TextAttr);
A line break is optional after local const, type, var declarations if they contain only a single declaration (but it is possible to have multiple identifiers in a single line).
procedure Baz; var Foo, Bar: Integer; begin ... end;
Of course, this is also accepted:
procedure Baz; var Foo, Bar: Integer; begin ... end;
But don't follow this example:
procedure Baz; var Foo, Bar: Integer; Qux: Real; begin ... end;
If you have many declarations you can break lines several ways. The following is the preferred form for var declarations:
var Foo, Bar, Baz, Qux, Quux, Corge, Grault, Garply, Waldo, Fred, Plugh, Xyzzy, Thud: Integer;
or:
var Foo, Bar, Baz, Qux, Quux, Corge, Grault, Garply, Waldo: Integer; Fred, Plugh, Xyzzy, Thud: Integer;
This one, instead, is more suitable to record and public object fields, especially if there's a comment for many or each of them:
var Foo, Bar, Baz, Qux: Integer;
No line break after var declarations within statement blocks, because they allow only one declaration, and doing a line break would look like further ones were allowed.
Foo := Bar; var Baz: array [1 .. Foo] of Integer;
As they are a GNU Pascal extension, use these declarations sparingly, for example for variables whose size depends on values computed within the routine, or for variables within unit or module initializers or finalizers to avoid global variables, although you might want to think about using a subroutine.
Do not insert a line break after label. This is how you should declare labels:
label Foo, Bar, Baz;
And, for completeness, here's how not to do it:
label Foo, Bar, Baz;
Several declarations in different lines don't even work:
label Foo; Bar; Baz;
Here's an example on how to use line breaks within a case statement.
case foo: begin ... end; bar, baz .. qux: ... else ... end;
Or (“tabular”):
case foo: begin ... end; bar, baz .. qux: ... else ... end;
Long statements or declarations should be broken either always before operators or always after them (where the extent of always is at least one routine) or after a comma, with indentation such as to make the meaning clear:
if (x = y) and (foo or (bar and (baz or qux)) or fred) then
or:
if (x = y) and (foo or (bar and (baz or qux)) or fred) then
Here's how to use line breaks within if-then-else statements. Another use for it is where you would use a case statement if it was possible, but it isn't possible (for example because the types are not ordinal, or the values to be compared to are not constant, or the comparison involves a function (StrEqualCase, or there are additional conditions).
if ... then a else if ... then b else c
If a and non-a are main cases, and b and c are sub-cases of non-a, use the following (the distinction might be a matter of taste sometimes):
if ... then a else if ... then b else c
The following (biologically quite incomplete) example contains a mixture of both forms which we consider reasonable:
if Habitat = 'Water' then { Animals living in water } WriteLn ('Is it a fish?') else if Habitat = 'Air' then { Animals living in air } WriteLn ('Is it a bird?') else { Animals living on land } if Legs = 8 then WriteLn ('Is it a spider?') else WriteLn ('Is it a gnu?')
The main cases are determined by the habitat, and the number of legs determines some sub-cases.
For normal control loops here's a brief list of possibilities:
for ... do ...
while ... do ...
repeat ... until ...
If there is only one command after the if clause, or in a for or while loop, or between repeat and until, and if that command is short enough, you can put the statement on one line only, like this:
if ... then ...
for ... do ...
while ... do ...
repeat ... until ...
Here's how to behave when begin and end are involved.
if ... then begin ... end
for ... do begin ... end
while ... do begin ... end
The indentation is 2 characters wide, for each begin, then, else, case, do (for, while, with, to begin, to end), repeat, record, object, type, const, var, label.
The bodies and local variables etc. of global routines must not be indented, just like global variables etc. Each subroutine (header and body) and its declarations, on the contrary, must be indented.
program Prog; var GlobalVar: Integer; procedure GlobalProc; var LocalVar: Integer; procedure LocalProc; var LocalLocalVar: Integer; begin WriteLn ('This is a local procedure.') end; begin WriteLn ('This is a global procedure.') end; begin WriteLn ('This is the main program.') end.
Variant records should be indented as follows:
type Foo = record NonVariant: Foo; case Discriminant: Bar of Val1: (Variant1: Baz; Variant2: Qux); Val2: (Variant3: Fred) end; var Foo: record [ as above ] end = [ initializer ]
Bigger indentation, i.e. more than 2 characters wide, can be used to break statements or declarations or to get a “tabular” code.
Conditionals ({$ifdef}) should be on the same indentation level as the code they affect:
begin {$ifdef DEBUG} WriteLn ('Debugging version'); {$endif} ... end;
Short conditionals which affect only an expression can be written within a single line:
Foo := {$ifdef DEBUG} 'debug' {$else} 'release' {$endif};
If they are intentionally used in a way contrary to normal syntactic rules, put them where they seem to fit best and write a comment:
begin { Do the code unconditionally if debugging } {$ifndef DEBUG} if SomeCondition then {$endif} begin ... end end;
Most times you will find a nicer and not less efficient way of writing the same statements. In this case, it can be done this way:
begin if {$ifdef DEBUG} True {$else} SomeCondition {$endif} then begin ... end end;
Or better yet:
{ globally } const DebugFlag = {$ifdef DEBUG} True {$else} False {$endif}; begin if DebugFlag or SomeCondition then begin ... end end;
Most rules we have covered so far do not apply within strings. In general, messages contained in strings should follow the GNU Coding Standards, for example, put quoted names within ` and ', although this means you have to double the ' in a Pascal string. See Errors (standards), for more information.
Normally you should use strings enclosed in single quotes, like 'this nice string that you are reading'. Use strings in double quotes when you need C style escape sequences like "\t". Note that NewLine ("\n") is predefined, so using NewLine is preferable unless you have to use a C style string for other purposes.
You can use multiline strings like the following:
WriteLn ('Hello world')
or (perhaps preferable, especially if the text in the string contains paragraphs and/or indentation itself):
WriteLn ( 'Hello world')
However, it is also possible to use:
WriteLn ('Hello' + NewLine + 'world')
(Note that the above example won't compile without using the
GPC
unit.)
Or, of course:
WriteLn ('Hello'); WriteLn ('world')
When you want to check if a string is empty, use this syntax:
if s = '' then ...
The GNU Pascal Compiler will eventually optimize it to the following more efficient test, hence you can use the previous, shorter one with no regret:
if Length (s) = 0 then ...
The same applies for <>, of course, and even for assignments where s := '' is the recommended form and will be optimized by GPC to SetLength (s, 0).
Please note the description in the GPC manual on how to do so (see I18N (gpc)).
This section of the GNU Coding Standards also applies to GNU Pascal. Remember that mmap actually means MemoryMap in this context. See Mmap (standards).
We recommend reading the respective section in the GNU Coding Standards, as it applies to this context, too. See Documentation (standards). There are some notes worth writing here, though.
As far as man pages are concerned, it would be nice to have a man page referring to the Info documentation. There is a GNU program, called help2man, which generates a man page based on the --help and --version outputs of a program. It works well, except that it always prints FSF which is not correct for all programs compiled with the GNU Pascal Compiler, but the output can easily be changed (for example, automatically using sed).
However, don't put too much effort in man pages. They might be feasible initially, but keeping them up to date together with the Texinfo files means a lot of work. On top of that, if you don't keep them updated, they are likely to cause more confusion than they help.
On the one hand, if man pages are shortened too much they are likely to miss important information. On the other hand, if not shortened, they get hard to navigate.
In other words, devote to Info (i.e., Texinfo) documentation.
Please read the respective chapter in the GNU Coding Standards. Note that the huge auto-tools effort of C is not needed for normal GNU Pascal programs. Also Makefiles are often not necessary in GNU Pascal. See Managing Releases (standards).
For your Pascal project you probably won't need large Makefiles and you won't need to use autoconf or automake. You can give the --automake to the GNU Pascal Compiler so that it takes care of dependencies for you. (As of this writing, the GNU Pascal Compiler's automake feature has some slight bugs, but they will be fixed. Also, there is a plan for a utility called gp, which is now under development, which will simplify the compilation process a lot more. Stay tuned. In any case, you usually don't need to write complex Makefiles yourself.)
A simple Makefile may be in order, like:
GPC_FLAGS=-O2 all: foo foo: foo.pas unit1.pas gpc --automake $(GPC_FLAGS) foo.pas mostlyclean: -rm -f *.o *.gpi *.gpd core clean: mostlyclean -rm -f foo distclean: clean extraclean: distclean -rm -f *~* maintainer-clean: extraclean
You may, however, want to put other rules into a Makefile to build documentation, data files, making distributions or whatever. Such things are outside of the scope of this text. You can usually do the Pascal compilations with a single gpc --automake call per program.
Routines are procedures, functions, constructors, destructors or (user-defined) operators.
Declarations are those parts of a program that “announce” the existence and properties of certain objects like constants, types, variables, routines, units, modules and the program.
Statements are those parts of a program that actually “do” something. A single statement is an assignment, a procedure call, a jumping statement (goto, Exit, Return, Break, Continue), an assembler statement, or a compound statement (begin ... end, if, case, repeat, while, for, with) which in turn may contain one or several statements.
Identifiers are those language elements that give names to objects like routines, constants, types, variables, units, modules. They can be (locally) redefined, unlike keywords which are part of fixed syntactic constructs (for example if ... then ... else) and cannot be redefined. Macros are no language elements at all since they are expanded by the preprocessor and never seen by the compiler.
Endianness means the order in which the bytes of a value larger than one byte are stored in memory. This affects, e.g., integer values and pointers while, e.g., arrays of single-byte characters are not affected. (see Endianness (gpc))
Note: Other items may be inserted here when it appears useful. If you'd like a definition of some other term, let us know.
MemoryMap
: MemoryMap