User:Kai Burghardt/Style guide
From Free Pascal wikiJump to navigationJump to search
- no Hungarian notation
- Hungarian notation is the naming style, where identifier start with letters associated with certain type categories. Always give meaningful names.
- camel-case identifiers
- Pascal is case-insensitive.
- Identifiers do not contain underscores.
- Do not write snake-case identifiers, unless they originate from foreign libraries (probably written in C). Also, this facilitates reading scoped identifiers containing dots. Both, underscores and dots are allowed to appear in identifiers, but only the latter has a special meaning. Since both characters are, with respect to their graphical appearance, “small”, it is best to use one of those small characters only.
- names optionally follow a hierarchy
- E.g. there are the range types
fooCodomain, both starting with
foo. Or, in another example, there are
staffMember = record … end;and
staffMemberReference = ^staffMember;, both starting with
staffMember. So related identifiers could appear next to each other in an alphabetical listing of them. But do not enforce this idea.
- Note: Unit scopes and namespaces automatically form a hierarchy. Ensure the fully qualified identifier does not contain any redundancies. Counter example:
mouseunit. The fully-qualified identifier is
mouse.showMouse. The word “mouse” appears twice. This is not nice. A better name for the procedure would have been (using the same verb) just
show. If the programmer using the unit needed or wanted to emphasize what element is being shown, he could write the fully qualified identifier.
- Do not abbreviate within identifiers. At no point, ever.
- Being lazy and abbreviating (or worse), does not improve readability. Although it is tedious to spell out everything, it will serve you well when revisiting code that hasn’t been seen for months. Don’t save money in the wrong place. Properly named identifiers are a case in point.
- plural nouns refer to collections, singular nouns to individual objects
- e.g. there is an enumeration type
mode, then the data type
modes– plural – will refer to a
set of mode(or other sort of collection)
- Every line contains at most one statement/declaration/definition!
- Always write at most one statement, declaration or definition in one line! Although it may be tempting to write a swap in one line
tmp := x; x := y; y := tmp;, do not do that. You still may align your code (with spaces):but in this example it does not help, so only do it if it is helpful.
tmp := x; x := y; y := tmp;
- Indent with tabulators.
- They take one byte, versus two or more bytes for spaces.
- Always write
endwhere it is allowed.
- This will minimize risks of erroneously thinking something belongs to a certain language construct.
repeat … untilhave their own
begin … endeven though it is redundant.
- Unary operators are not separated by a space from their operand, unless it is a word.
- Otherwise one could write
40 - - 2which just looks ridiculous.
- Binary operators are surrounded by a single space on each side.
- Otherwise one could write
40--2. I don’t like that. Write
40 - -2and we’re friends.
- An opening parenthesis starting the parameter list always follows directly the identifier.
- Do not write
writeLn (42). The parameters “belong” to the identifier, thus ought to be right next to them. Write
writeLn(42)with no blank inbetween and we’re good.
- Function calls are always followed by a parameter list, even it is empty.
- Always write
lastError := IOResult();explicitly providing an empty parameter list (i. e. “
()”). Without doing so, a non-familiar programmer reading your code could assume that
IOResultwas a (global) variable that can be read multiple times in succession, but this is in fact not true. After calling
IOResult()the underlying variable
inOutResis reset to zero.
- Note, however, that procedure calls may (and usually should) omit empty parameter lists. By their position (i. e. not being part of an expression) it is obvious that they are indeed procedures.
- use the strong typing system to your advantage
- Consider the following “wrong” piece of code (on a 64-bit platform):
function foo(const x: qWord): qWord; begin foo := x + 7; end;
- While you don’t necessarily use range and overflow checks in a production program, Pascal allows you to thwart many errors already at compile-time. In general, define domains and co-domains of routines in a manner, where they are actually defined. That means for the example above
type fooDomain = 0..high(qWord)-7; fooCodomain = 7..high(qWord); function foo(const x: fooDomain): fooCodomain; begin foo := x + 7; end;
- Of course this is a trivial example, but consequently employing this technique makes it possible to spot errors via simple range checks. (see also tutorial: defensive programming techniques)
- Do’s and Don’ts
- Coding style (FPC), design guidelines (Lazarus), Nomenclature
- the power of 10