You are on page 1of 161

Manual on

Object Pascal
Style Guide
Alexandria edition
By Bent Normann Olsen

NORM4NN
This page is left empty intentionally.
This manual is licensed under a Creative Commons
Attribution-ShareAlike 4.0 International license.
Full license:
https://creativecommons.org/licenses/by-sa/4.0/
Historical and latest editions of this manual is available at norm4nn.dk:
https://www.norm4nn.dk

2. edition, 1. revision, written with Trial Edition of

Delphi 11.2 – Alexandria


Copyright © 2022, Bent Normann Olsen, Certified Delphi Devel-
oper and Component Writer. All rights reserved. Document layout
and graphics by Bent Normann Olsen.

No proofreading done in English.


Based on the original Object Pascal Style Guide by Charles Calvert
from Borland (now Embarcadero Technologies) and the new Ob-
ject Pascal Style Guide led by Marco Cantu from Embarcadero.

"Delphi" is a trademark of Embarcadero Technologies, Inc.


Content

Preface .......................................................5 4. General Rules ..................................... 22


InfixCaps ...............................................23
1. Introduction .........................................7 Identifiers ..............................................24
Why a Manual ....................................... 8 Pascal Case ...........................................25
Significance ............................................ 9 Scope of enumerators .........................28
Terms and Definitions .......................... 9 Acronyms and Abbreviations ............30
Keywords ..............................................32
2. Overview ............................................ 11 Indentation ...........................................34
Source Files .......................................... 11 White Spaces ........................................34
Naming Convention ............................ 12
White Spaces Usage ............................ 12 5. Descriptive and Meaningful ............. 37
Comments ............................................ 13 Descriptive Names ..............................39
Classes and Interfaces ......................... 13 Meaningful Names ..............................41
Statements ............................................ 13 Recognizable Identifiers .....................42
Intention Revealing Names ...............44
3. Significance of Style Guides ............. 14 Misleading Names...............................45
Management and Style Guides.......... 15 Noise in Names....................................46
Legacy Code ......................................... 17 Pronounceable Names ........................48
Discussions on Style ........................... 18 Component Names on Forms ...........49
Object Pascal Style Guide ................... 20 Prefixes in Names ................................50
Naming Best Practice ..........................52
6. Comments and Intention ................. 54 Indentation ........................................ 111
Comment Policy .................................. 55 Space .................................................. 122
Comment Intention............................. 56 Line Break .......................................... 131
Code-level Documentation ................. 59 Capitalization .................................... 150
Code-level Comments ......................... 60 Align ................................................... 154
Refactoring of Comments .................. 61 Postscript ........................................... 159
XML Documentation .......................... 63
Section Headers ................................... 67 10. Epilogue ......................................... 161
Debugging Comments ........................ 72
Comments and Best Practices ........... 72

7. Statements ......................................... 75
Inline Statements ................................ 76
if then else Statements ........................ 77
for, while, repeat Statements ............. 81
case Statements ................................... 84
Handling if Exceptions ....................... 85
Functions and Procedures.................. 90
Parameters ........................................... 91
with Statements ................................... 91
Other Statements................................. 94
Exit Routine ......................................... 94
Break, Continue, other Routines ....... 96
Code Formatter and Statements ....... 96

8. Classes and Interfaces....................... 97


Structure of a Class.............................. 97
Methods ............................................. 100
Class Methods and Class Variables 101
Interfaces ........................................... 105
Other Topics ...................................... 106
Compiler Attributes .......................... 106

9. Code Formatter ............................... 109


Profiles ............................................... 109
Preface
27 years ago, like so many other developers at the time, I was dazzled by a new IDE tool
from Borland that was reviewed in one of the magazines back then. Innovative in being
able to drag and drop components from a pallet to a form and write code afterwards, mo-
tivated my curiosity. I ordered Delphi and it probably cost about DKK 2,500.00 in 2022
prices with shipping. There were four books included with the software package and one
of them was titled "Component Writer", which both inspired my aim to develop compo-
nents and pursue a career as a professional developer. The books were not my only
source of inspiration, because the source code for VCL (Visual Component Library) also
gave a view on how professionals constructed code. I also wanted my work to appear like
code written by a professional developer, and at the time I didn't know about the exist-
ence of a style guide from Borland. Instead, the libraries gave me what we would today
call "best practice" on how my code should be constructed according to their style, which
was most likely mixed with bad habits from the days of Turbo Pascal.
Today, I like to advocate the idea of better quality in software that is shaped by formal
style guides and Coding Best Practices. This thought is also encouraged by principles or
concepts behind, among others, "Clean Code" and "Refactoring", and developers who
have read the books will also nod in recognition that those books also recommend a
standard style guide. Most people also know that Coding Conventions are far more far-
reaching than just a coding style, and therefore this manual will try to reach out to Coding
Best Practices, and to some of the thoughts behind the mentioned books, where the Ob-
ject Pascal Style Guide has shortcomings. Wikipedia on "Coding Conventions" gives a
good overview of what an adequate guide should include, just as it has a list of coding
standards for specific languages. However, the link to Object Pascal brings us to the old
Object Pascal Style Guide.
This manual will emphasize the value of these thoughts as well as the disillusionment
with arbitrary coding style. It's probably no secret that developers often disagree about
whether to use prefixes in parameter names, which prefixes if any, and whether letters
should be capitalized. It is not just opinionated discussions, but also about unwillingness
and sometimes controversy, which makes it important to talk about formal and especially
objective guidelines, rather than ignoring or dismissing them because of personal prefer-
ences. Developers who have worked in large teams with arbitrary attitudes have experi-
enced the importance of standards.
Bent Normann Olsen
Denmark,
November 2022.

6
Chapter 1
Introduction
Marco Cantu, RAD Studio Product Manager at Embarcadero Technologies, announced in
April 2021 on his blog that they had released an updated version of their Object Pascal
coding style guide. He wrote that they have added guides for new features that include
modern language features and made a few changes to the original guide. That last sen-
tence made me a little nervous, but only until it became clear that they had been loyal to
the old guidance, i.e., that the groundwork of the coding style remains. More specifically,
sections have been added on newer features of the language, including Generics and
Anonymous Methods, and a few rigid rules have been removed, such as capitalization for
all acronyms, and the document has been revised to fit Embarcadero's docwiki style.
However, many of the new language features in Object Pascal have been available for
years, and this is in relation to the fact that the original guide was published around the
time of the first versions of Delphi – with only a few changes in the first subsequent years.
Like the original guide, the new guide is a recommendation. Similarly, the new guide and
this manual prefer to use the auxiliary verb "should", with a motivation of what would be
the right thing to do. Despite this gentle approach, the guide serves as a formal standard
for the Object Pascal dialect of Delphi, as well as required for the R&D developers at Em-
barcadero and their partners. It applies to all guidelines that are mandated by teams
within a project or specified as a requirement within a company, that verbs such as
"should" are then read as a stipulation of writing code as recommended. It can be difficult
words for programmers with strong opinions about coding style that may not be exactly
in line with their own style.
I refer to their guide as a standard, in the sense of "accepted as the norm". Being the most
prominent dialect of Object Pascal that is constantly being worked on, with the earliest
dialect of Object Pascal abandoned by Apple many years ago, as well as other open-
source projects aiming for compatibility with both the Object Pascal dialect in Delphi and
the style guide, then it is not difficult to consider the Object Pascal Style Guide as a de
facto standard. Most open-source projects that incorporate the Object Pascal language
has references to the original style guide for Delphi, just as the guide appears as a coding
standard on Wikipedia on Coding Conventions.
I've probably stepped on someone’s toes when I talk about the original or the new guide
as being a standard. But a standard does not have to be elevated by e.g., International
7
Organization for Standardization (ISO) to be considered a standard. Nor is there any in-
stitution on ISO-level that would consider drafting documents with language-specific
coding styles as standards. A body like ISO would specify the semantics and syntax of a
programming language, as nicely demonstrated by a statement in "Pascal ISO
7185:1990" that their standard does not specify: "f) the typographical representation of a
program published for human reading."
The word "standard" can in some way be a scary term for some developers, even if it is
simply in the sense of being a guide that is accepted as being the norm, and at the same
time serves as a means of measuring the expected level of quality – an expected standard.
We just must keep in mind that if a company specifies a coding style for its developers,
then their current guide should be seen as a standard at that company. They could also
specify an arbitrary coding style, but then the company will be in opposition to Coding
Best Practices. In that context, it is also considered counterproductive to use one and the
same coding style across different programming languages.

Why a Manual
Guidelines can be very unvarnished in the wording of recommendations, abbreviated
with a few examples, and rarely describe the range of words used, e.g., "method names
should be imperative verbs or verb phrases". Style guides thus assume that we under-
stand the technical terms and grammatical functions used in a tutorial and that we have a
basic idea of how to construct code. The purpose of this manual is therefore to become fa-
miliar with wording in the Object Pascal Style Guide, the scope or consequence of a rule,
and to help set up the Delphi IDE to support a coding style. And not to neglect the im-
portance of a coding style guide.

"Though we believe in, and admire the style promoted in these


pages, we support them not necessarily because we believe they are
right and others are wrong, but because we believe in the efficacy
of having a standard which most developers follow."
– From the original Object Pascal Style Guide.

The Object Pascal Style Guide is primarily a code (or programming) style guide, with a
set of rules and guidelines for programming, structuring, and constructing Object Pascal
code. A guide establishes formal requirements for code style based on readability and that
it is easy to maintain because consistency is ensured both in files and across an entire
software system and teams. Consistency according to a style guide also encourages easily
recognizable code constructs in the same way that Software Design Patterns encourage
recognizing reusable concepts for commonly reoccurring code constructs. By getting used
to standards, we recognize familiarity in code and understand the intention much more
easily. For the same reasons, Embarcadero also recommends their style guide for Delphi
developers in general.

8
Significance
The importance of a style guide can also be demonstrated by the simple fact that ques-
tions about coding style that are often asked on various forums are most often closed. Ei-
ther because the question does not fit a Q&A format or coding style is considered off-
topic, but especially because the topic will incite discussions with sometimes heated ex-
changes. The same opinions and attitudes can affect collaboration and unity in teams –
even in teams we ourselves are part of. Misjudging the importance of a specified coding
style for a project or teams, and allowing developers to use arbitrary coding styles, can
tear a team apart and significantly lower the quality of software. By that fact alone, coding
style formalization should also be considered a critical management-level goal. It is also
for such reasons that we see requirements for coding style at the organizational level in
companies with a professional approach to software development.
In addition to the intentions of style guides, this manual will provide an overview of the
changes from the original guide to the new guide. We can then choose to narrow down
few focus areas if we are already well-grounded in the original style guide. This manual
will also help to describe the real scope of the style guide as it stands, and in the same vein
remove misunderstandings such as "it does not specifically state that the first letter of pa-
rameter names must be capitalized". This is already covered by the phrase "all identifiers
must follow the general rule of using Pascal Casing", e.g.:
// INCORRECT
procedure SetPosition(aValue: Integer);
// CORRECT
procedure SetPosition(AValue: Integer);

The manual will also give an idea of how we can take advantage of Coding Best Practices
for coding style in areas not covered by the guide. Guidelines are not always specific in the
rules, and most often use general terms, just as the examples must be seen in a wider con-
text. This manual will thus add the concept of "Clean Code" to coding style in areas that
neither the guide nor Coding Best Practices cover. We just must ignore that the examples
in "Clean Code" are written in Java language and use Java language coding style, and that
for that reason we do not discard the recommendations of the Object Pascal style guide.
This manual should provide a pragmatic view on how we evaluate a given code style
against the Object Pascal Style Guide. The manual will also give an insight into how we
set up Delphi's Code Formatter and let the editor do the most basic work of applying a
code style.

Terms and definitions


There are a few terms that can be highlighted and perhaps clear up a few misunderstand-
ings.
"Naming Convention" and "Capitalization Rule" are not used in this manual interchange-
able as in the misconceptions of naming conventions are about capitalization of letters

9
only. A naming convention is a set of rules in how to produce a proper name, and nor-
mally also incorporate capitalization rules for different types of names. As an addition of
the term "capitalization", this manual often uses the term "stylization" in relation to capi-
talization of names. Stylization is a word that is closely related to style guides, meaning to
conform to a particular style, and therefore also in this respect a common term.
"Programming Style" and "Coding Style" are used in this manual interchangeable regard-
less of never-ending discussion on "Programming" vs. "Coding" – both are the process or
activity of writing computer programs, and style is a set of rules when writing source
code, enhancing readability and quality of the code.
"Code Constructs", or just "Code", is used to define the entire structure of statements, dec-
larations, and definitions using language syntax and symbols.
"Standard", or "de facto standard", are terms used in the sense of accepted as normal, and
the expected level of quality.
"Formal" and "arbitrary" are used in distinguishing a written style guide, and informal
and unwritten style.
"Developer" and "Professional" is used to emphasize the difference in typical roles of a de-
veloper, and those of a professional working according to standards of practices and eth-
ics for a particular field.

Image by xkcd.com, and licensed under a


Creative Commons Attribution-NonCommercial 2.5 License.

10
Chapter 2
Overview
When Marco wrote that there were "some changes to the coding style", my next
immediate reaction was "where?" Of course, we cannot ask for an overview of where and
how the guide has been updated, so we can actually start with the most obvious and
summarize the differences by setting up a comparison of the old and the new style guide.
After the overview, and thoughts on the meaning of a code style, chapter 3, the manual
will go through the guide's other main topics. The manual will also add recommendations
for features of the language not covered by the original or the new guide, e.g. with,
try/finally etc. In the same way, the manual will help expand the recommendations,
by e.g. also offering a set of prefixes in addition to T for classes (Type), F for object
variables (Field), I for interfaces etc.

Source Files
The recommendations in the old "Source Files" have been moved to the new "Source
Code Files, Units and Their Structure". The principles of files are generally preserved, but
the old Win32-centric recommendations have been changed to a more multiplatform-
friendly description, and a recommendation to use unit scope names, e.g.,

Tabel 1.1 Oversigt over kapitler


Original vejledning: Ny vejledning:
Introduction Introduction
General Rules: Identifiers, Keywords, Indentation
Source Files Source Code Files, Units and Their Structure
Naming Conventions
White Space Usage White Space Usage
Comments Comments
Classes
Interfaces
Statements Statements
Type Declarations

11
Vcl.Forms.pas. However, the entire section on declarations of classes and interfaces,
apart from declarations of uses, has been moved to the new "Type Declarations". The sec-
tion is no longer part of how the file is organized and structured with declarations, having
been given its own chapter in the new guidance.
If you have read the new guide carefully and looked at the examples, you will also have
noticed that there are no blank lines between the required sections. It is mentioned that at
least one blank line must separate each of these sections, and it is also mentioned in the
original style guide, just as the original examples have blank lines, which is why the new
examples may appear ambiguous. It is not likely that they forgot to remove the recom-
mendation, but more likely that they simply forgot the blank lines in the examples, or that
the blank lines were "optimized out" in a copy-paste maneuver. Regardless, this manual
will show examples of what they should look like according to the descriptive part of the
recommendation. At some point they will probably have the examples revised.

Naming Convention
"Naming Convention" is no longer a separate chapter and the original sections have been
moved to a more appropriate section in the new guidance. For example, "Method Nam-
ing" is now part of "Class (and Record) Declarations", which in turn is a section under the
"Type Declarations" chapter. The new section has some clarifications but is largely con-
sistent with the original naming convention.

White Spaces Usage


"White Space Usage" is still a separate chapter and some points have been added to sup-
plement the original points. Apart from a single "it's okay with a blank line in certain
places", there are now explicit points for where we should not use blank lines, and explicit
points for where we should use spaces. Indentation is still the same and the new guidance
has been clarified with examples of what is correct and what is not correct.
"Continuation Lines" has been shortened a bit, perhaps in favor of more examples on in-
dentation and because the section included general guidelines and therefore moved to
"General Rules: Identifiers, Keywords, Indentation".

Image by xkcd.com, and licensed under a Creative Commons Attribution-Non-


Commercial 2.5 License.

12
Comments
The chapter with "Comments" has also been slightly updated. Original recommendations
for block and single-line comments still apply, but the examples have been removed. Per-
haps because these were simple recommendations and that now space had to be created
for or focus should be on recommendations for comments in XML format.

Classes and Interfaces


The chapters on "Classes" and "Interfaces" have been moved to "Type Declarations". It is
in that chapter where the recommendations have been given a boost, and where we will
find recommendations for Generics, Anonymous, Attributes and others.

Statements
Guidelines on statements is largely the same as in the original guidance. We can find a
few new guidelines, e.g., inline variables, just as some examples have been removed and
others have been added.

Image by xkcd.com, and licensed under a Creative Commons


Attribution-NonCommercial 2.5 License.

13
Chapter 3
Significance
of Style Guides
The purpose of style guides is to ensure consistency across source code with a focus on
readability, despite the fact that code may have passed through the hands of many devel-
opers. The purpose of this manual is to gain a attitude on the importance of a formal style
guide versus arbitrary styles, or no coding style at all.
This manual also highlights conscientious reasons why style guides are considered Cod-
ing Best Practice. It is quite normal for professionals from different fields to recognize
Best Practices as the best tried methodologies or techniques. Style guides are aspects in
improving quality and thus a fundamental part of Coding Best Practices. In other words,
arbitrary coding style, or no style at all, is considered bad practice or bad habits in devel-
opment environments in general and can almost be categorized as anti-pattern.

Coding Best Practice: Follow a language standard,


and don’t use capitalization rules inconsistently.

A specified style guide will affect many types of people differently, and depends on their
personality and temperament. Therefore, it is also necessary to look closer at the types of
people who can make up a team of developers. We must not think prejudices about
developers, but that professionals from different fields can also be involved in a project
who have different expectations on practices. And with the diversity of the modern age in
mind, and without being biased, we should also be able to recognize that programming
tends to attract introverted people. It can be wise to be aware of the tendencies in a
development team, for instance, to be able to appreciate developers with Asperger's
Syndrome. Some can be critical of others' work, without ever raising any voice, but
extremely forgiving when the work has been done in accordance with rules and
procedures. Arbitrary attitudes can therefore also discourage one group of developers
more than others, pushing them out of a team.
Some studies on developer aversions will also place "other people's bad code" high on the
list. Inexperienced developers, perhaps unsurprisingly, rarely appreciate the importance

14
of a formal style guide, and may also not understand the purpose of a style guide, thus
working in opposition to a practice of coding style standardization. We often hear "I like
this better" or "I prefer" and may try to impose a personal preference on an entire team.
Ironically, they may end up maintaining "other people's bad code" who may also have
had problems with style guides. The result is just bad code being replaced with another
kind of bad code, and then we're really into anti-patterns, e.g., "Software Rot", because the
code slowly erodes over time.
It is also a common trait of the attitude towards programming in e.g., "cowboy coding";
an absence of formality, compared to organized development methodologies that most
professionals would prefer. To elaborate, a "cowboy coder" is usually a lone developer or a
member of a team who works without formal methods and with very little discipline. It is
also an indirect statement that professionals would rather prefer agile principles, as we
see in e.g., Scrum and the frameworks within software development, rather than "cowboy
coding", unless Scrum and terms are misused to obscure dysfunctionality and rather re-
sembles "ScrumBut".
Most professionals appreciate formal frameworks as a way to introduce rules for how and
when we work together across different roles. Formal style guides will similarly be objec-
tive, based on Coding Best Practices and concepts. It may not seem important to other
people, or to a management, but developers actually have habits and strong opinions
about indentation, spaces, capitalization, etc. And developers can tend to change "other
people's bad code" to something that matches with their own opinion. This is also the
case if an arbitrary style was enforced and the code that was replaced actually conformed
to a real style guide.
This cycle of developers replacing fragments of "other people's bad code" continues for the
rest of a system's life cycle, eroding into a maintenance-heavy system of software entropy.
Remarkably, it is not a rare scenario, and it is a particularly costly reshuffle of developers,
and not least in a product of an unmanageable system that is also notorious for prevent-
ing companies from adapting to new situations.

Management and Style Guides


In short, we do more damage to a piece of software if we, as a software development
manager, software architect, lead developer or perhaps a "heavy" senior developer, just
keep defending an arbitrary coding style.
So far, we've uncovered a few key motivations for appealing to a management to specify
formality: 1) No manager likes the result of a constant cycle of developers or wants to re-
tain an unhealthy working environment due to bad practices. And it will be "due dili-
gence" to assume that 2) managers will prefer manageable systems that can be replaced
or extended, and in particular be valuable if they can be easily adapted to new strategies
or changing needs and new technologies. In other words, history has also shown again
and again that bad code can bring a company to its knees.

15
Professionals should be competent enough to choose an appropriate style guide for a pro-
ject themselves and are expected to do so. Management should simply ensure that an
agreed coding style is a validated style, in part to avoid assertive developers, e.g. "cowboy
coders", etc. This is a moment where a management has the opportunity to ensure quality
for their assets and ensure that any future developers do not inherit a coding style based
on arbitrariness. Ultimately, a management may have to consider specifying organiza-
tional requirements for style guides for different types of projects, and perhaps also for
business partners and contributors of code. For third parties, it is far more attractive to be
required a standard style guide than to be forced into a style arbitrary to them.
Software engineers in particular will acknowledge that program comprehension is an
important topic in software development and maintenance. That is why we also see
program comprehension as a field of research at IEEE (Institute of Electrical and
Electronics Engineers). They regularly publish results on research in the subject and
regularly host the International Conference on Program Comprehension (ICPC). For
engineers, and for all forms of functionality, it is often about standards.
The topic is important because in the early stages of software development, developers
build an understanding of a program in code and operation, but this information is lost
when developers are scattered in all directions. Once the information is lost, it is practi-
cally impossible to recover. Therefore, we often need a practice that supports program
comprehension when parts of the code need to be modified later. Style guides play a role
in that work. And that role should be recognized as crucial, because program comprehen-
sion can become a big problem in understanding precisely how a program behaves when
we only have existing source files as a reference. Part of comprehensibility is related to
code style in which a software will present itself as it is developed, even before it is in the
maintenance phase. Some studies suggest that program comprehension accounts for 50%
of maintenance costs.
In contrast to documentation requirements of software, domains, or e.g. descriptions of
APIs and the like, constructions of code are difficult to document. We can of course easily
skip over this difficulty as agile values such as "working software over comprehensive
documentation" become popular. In this regard, the agile manifesto is probably also

Image by xkcd.com, and licensed under a Creative Commons Attribution-NonCommer-


cial 2.5 License.

16
misinterpreted, because it says that we must avoid "comprehensive" documentation, but
not documentation in general. Nonetheless, developers are expected to understand what
a program is supposed to do by only using source files as a reference before making
changes. This expectation implies the necessity of methods that support exactly program
comprehension.
And in certain business fields, developers are expected to be responsible for their code,
which in turn must go through reviews by other professionals, where every single state-
ment and construction is scrutinized and verified before it can be included in systems, be-
cause the code can affect people's safety and lives, or that these are code assets with huge
values at stake. Fault-tolerant code is still a requirement in just as many fields, and I've
seen, for example, a developer trainee fail a review because a reviewer chose to pull a con-
nection in the middle of a review. The software crashed and was unable to continue.

Legacy Code
"Legacy Code" does not mean that software consists of "other people's bad code." It
means that the code base has been written over many years, that it has seen better days,
but that it is still in use, and that it is especially evident in fragments of code that have
been changed by several developers over time. That type of code is also known to be vul-
nerable to "software rot", i.e., that it decays silently, and it can turn out to be bad for a
company if it is not followed closely. Legacy systems can be extremely costly to a business
in terms of limitations in strategy, missed opportunities, not to mention the problems
with maintenance, and seem appalling. Thus, we can highlight problems in recruiting de-
velopers because there may be no status in a position that just needs to keep a legacy sys-
tem alive. And others may express a definite fear of touching something in an old system,
and therefore try to avoid taking on certain tasks.
Legacy code that is constantly changing and will still be in use for a few more years, and
whose integrity we need to ensure, we should consistently put sensible and timely mea-
sures in place. This can include refactoring arbitrary code style into a formal code style.
No team should accept "coding as usual" to satisfy a few senior developers or because the
system is going to be scrapped soon anyway. In 10 years, the system, or parts of the sys-
tem, will most likely still be in use and a strategic target for a changing environment.
Refactoring code is a means of solving a problem of bad code. It is described as the pro-
cess of refactoring existing code to improve its constructs entirely without changing the
process or execution. This has the potential for improved readability and reduced com-
plexity, better performance, improved maintainability, and even opening up extensibility.
With sensible and timely measures, we not only ensure improved software quality, we
will also be able to more easily attract new developers who can replace "old" developers,
e.g. by openly encouraging Coding Best Practices, certification programs, formal agile
frameworks, favoring the principles of object-oriented programming and other para-
digms, recognizing Software Design Patterns, and welcoming collaboration in teams,

17
being up-to-date on the latest versions of programming and testing tools, popular ver-
sioning and revision control systems, and whatever else might attract developers.
Anything that can tell a constructive and positive story about leveraging the latest tech-
nologies and philosophies, and not least demonstrating a practice of technical profession-
alism, despite the code being part of an old system. The rather negative word "legacy" will
become quite unnecessary, regardless of whether there are actually established teams
working on a new system. Instead, all teams should embrace the old system with positive
talks, rather than negative talks. It will seem much more attractive to new developers.

Discussions on Style
The importance of a formal style guide can also be seen from a more serious angle, and
that is that a lack of formality can ignite attitudes among developers and in many cases
lead to disagreements. Even if the attitudes can be related to "other people's bad code"
and bad practices, which appear as trivial opinions about preferences, it becomes no less
crucial for a management to have a focus on.
Coding style has been a source of discussion between developers since before books like
"The Elements of Programming Style" were written some 50 years ago. The topic is not
unique to Object Pascal and is lively debated across languages, including low-level assem-
bly language. If that wasn't the case, then we wouldn't have needed to write style guides
and manuals about style guides either. Although a style guide contains only recommen-
dations, style guides have always been anticipated guides for many professional develop-
ers, as they can de-dramatize attitudes in a recurring dispute between developers that is
solely related to which style is "right". A few will also downplay the usefulness of a style
guide, simply to avoid recommendations and having to change style, thus standing in op-
position to moving towards Coding Best Practices.
An escalation can also arise from developers with a very personal style, in some cases re-
acting fiercely against the very idea that their style should be arbitrary. And perhaps un-
willing to even admit to having observed a formal style guide. Personal taste is notorious
for causing polarity among developers, and official style guides take up an important po-
sition here by de-dramatizing discussions, simply by being a de facto standard and espe-
cially being objective.
Some would also argue that such rules limit our ability to work on problems or be crea-
tive, and others would argue that compliance or non-compliance reveals the standard or
lack of professionalism of developers. Regardless of opinion, new developers will at some
point ask for style guides if they are particularly asked to correct their coding style. Soft-
ware development does not become a static thing just because we use a standard coding
style. Recommendations in a style guide do not free developers from being able to think;
developers can write code with different coding styles that result in exactly the same bi-
nary code. Rules and general guidelines just make it easier to transfer code between

18
professionals, and not just for code reviews, but if the code is to be maintained by people
other than the original developers.

“Any fool can write code that a computer can understand. Good
programmers write code that humans can understand.”
- M. Fowler (1999), author of "Refactoring”.

Personally, I've politely shrugged and referred to a standard style guide when asked to
adjust my coding style to an informal or arbitrary style – and calmly walked away from
such an approach. After all, I am a certified Delphi developer, and other professionals
should therefore also expect a certain degree of formality from my work. It is, among
other things, what we should expect from certification programs; guaranteed to be able to
meet a certain standard - also on quality.
Now, I'm not an Embarcadero MVP (Most Valuable Professional) evangelizing Embarca-
dero technology and their guides. In fact, we can find formal style guides for Object Pascal
in the public domain, including a guide from Project JEDI and from open source projects
like Lazarus. Their guides are based on the original Object Pascal Style Guide. We can
also find several dialects of Pascal, including Extended Pascal, defined by the standard
ISO 10206 (1990), and with GNU Pascal as an example. GNU Pascal has its own coding
standards and is probably more attractive in *nix-like development environments.

Object Pascal Style Guide


Use of style guides should not stand alone, but be supported by other concepts, e.g., may
be ranked as the following: 1) the rules from a formal style guide such as the Object

Image by xkcd.com, and licensed under a Creative Commons Attribution-NonCom-


mercial 2.5 License.

19
Pascal Style Guide, 2) Coding Best Practices, 3) and e.g., from the thoughts behind Clean
Code (and we disregard the fact that the examples are in Java language).
If you have read "Clean Code" by Robert C. Martin, then you will also know that a general
rule in his book is "Follow Standard Conventions", quote: "Every team should follow a
coding standard based on common industry norms". And if you have also read "Code
Complete 2" by Steve McConnell, then you will also have learned that "Programming
Conventions" are considerably important to avoid arbitrary coding style, because without
a coherent discipline our software will become "a jumble of sloppy variations in style".
Even "Refactoring", by Martin Fowler, would argue that code should be written to be un-
derstood by humans. At a minimum, the code should be written with the intent that it
will be understood by other professionals and that it can pass review, be reused, main-
tained, and improved.
In my years with Delphi, I have yet to meet a colleague, curiously enough, who knew
about the existence of the original Object Pascal Style Guide. I have met developers who
advocated "Clean Code", "Code Complete" and "Refactoring", but did not know of an Ob-
ject Pascal style guide. That circumstance has hopefully only been in relation to the com-
panies I have worked for. On the other hand, it's been encouraging to see developers em-
brace Embarcadero's style guide once they've found it. After all, we are professionals.
This manual is for developers of all levels; from beginners just starting to learn coding
style for Object Pascal, to more experienced professionals who just want to polish their
coding style to a shinier finish. And maybe find arguments for why formal style guides
are important. This manual is also a nice supplement if you plan to take the Delphi Certi-
fied Developer or Delphi Certified Master Developer exam and recognize yourself among
professionals. You will be asked questions about coding style – what is correct and what
is incorrect.
It can take years to get used to a formal coding style, just as it can take a decade to be-
come an expert in a paradigm like object-oriented programming. And yet even experi-
enced developers may find themselves needing to polish some corners of their coding
style. It's not about conforming to a coding style from day one, nor is it about absolute
conformity, but it's primarily about general conformity to a style guide.
Style guides are usually about the visual appearance of the source code with the aim of
making it more readable. And with features in Delphi, including Refactor and Formatter,
source code can be automatically formatted in many ways. Such features also make it eas-
ier to enforce coding style requirements, allowing developers to focus on naming, logic,
and other more important aspects of programming and not so much on coding style.
The absence of Pascal Case, also known as InfixCaps or Upper Camel Case, often stylized
as "UpperCamelCase", will probably be the most typical picture of source code that does
not adhere to a standard style guide. In many cases we also see lower camel case applied

20
to identifiers, which is a type of stylization usually recommended in other programming
languages.
Professionals who engage in style guide formalization and quality in general are often also
more likely to be encouraged by other characteristics of programming, such as the differ-
ent approaches and ideas of Software Design Patterns and the influence of philosophies
behind object-oriented programming as a paradigm and Coding Best Practices in general.
Complete absence of formality can be experienced as very unpleasant, both mentally and
for the overall quality of a piece of software. If you are a developer who go through the use
of an informal or arbitrary coding style in your team or company, ask your boss to read
this chapter. If you are a manager who experiences teams of developers discussing coding
style, ask your teams to read this entire manual.

21
Chapter 4
General Rules
Identifiers must be the right place to begin when we write about general rules, and the re-
lations around InfixCaps. No other rule in the new style guide has a greater impact on the
style than the general rule that "all identifiers should follow the general rule of using Pas-
cal Casing (aka, InfixCaps)". Clearly, we need to understand the concept of "identifiers" to
understand the scope or reach of such a rule.
Most naming conventions also have a strong focus on formulating meaningful names for
identifiers, when to use upper- and lower-case letters, how to use prefixes or suffixes and
where they are required, and how to divide compound words. Some conventions limit the
length of names, and others will recommend long names over short and vague names. At
the same time, there are other concepts, such as "Clean Code", which would suggest that
comments on names of identifiers are the result of meaningless names.

"If we had the talent to subtly wield those languages to express our intent,
we would not need comments very much – perhaps not at all.”
– Robert C. Martin (2009), "Clean Code”.

Examples of method names with the most common styling rules, and an abbreviation,
can be:

1) SetPosition or SetPos,
2) setPosition or setPos,
3) set_position or set_pos.

Pascal Case (also stylized as PascalCase) is the popular term for the Upper Camel Case
(1) variant (as in InfixCaps), just as the common term for "camel case" probably means
Lower Camel Case (2). Camel case was a popularized term early on in Windows environ-
ments, which was also stylized as camelCase. The last example above is a popular styliza-
tion called the Snake Case (3). Many conventions generally do not recommend names of
identifiers with abbreviations, such as shortening SetPosition to SetPos, but most often
recognize common abbreviations.

22
The new style guide prefers descriptive and simple words, although we can find familiar
and commonly found abbreviations in Delphi such as "Pos", "Max", "Min", etc. Many of
these abbreviations may be of historical origin, just as shorter names have been common
practiced in the early versions of Pascal and before we saw the any release of an actual
style guide. According to the new style guide, usable names must be imperative verbs or
phrases, be descriptive, with stylization according to Pascal Case, and avoid the use of ab-
breviations, for example:

• SetPosition

The name of the above method might suggest that it could be a setter for a property
named "Position". The name of the method is somewhat recognizable in its own simple
composition, without however being meaningful if it had been a global procedure and
was not fully qualified. If the method is a private member of a TTrackBar class, then "Set-
Position" will present itself as more meaningful. Therefore, we need to see an identifier in
a context to interpret its meaning, and that we therefore do not need to name the method
as "SetPositionOfTrackBar". More on that topic later.
Regardless of the previous tradition of abbreviating well-known words, we now see more
consistency in the use of full names, also across languages, and especially for members.
We prefer e.g., SetPosition rather than SetPos, but we will still see some alternative abbre-
viated methods, such as SetSelStart, which we also find in the same class. In order to
maintain meaningfulness, each compound name must be weighted so as not to be too
long, against the risk of being ambiguous.
An important difference between Object Pascal identifiers compared to most other lan-
guages is that there is no distinction between upper- and lower-case letters in Object Pas-
cal. This may be a major reason for maintaining strict rules for stylization in other pro-
gramming languages where names are case-sensitive. "SetPosition" is the same identifier
as "setPosition" in Object Pascal, but not necessarily in other languages.

InfixCaps
Den originale stilguide bruger udtrykket InfixCaps eller bruger i beskrivende vendinger
"lower case" og "lowercase" eller "capital". Pascal Case eller Camel Case er ikke brugt i den
originale stilguide, og i modsætning til dette hælder den nye stilguide således mere til
udelukkende at bruge "Pascal Casing". Problemet med InfixCaps er måske, at nogle få
navnekonventioner også bruger "InfixCaps" til Upper Camel Case og "infixCaps" til Lower
Camel Case. Med dette in mente forsøger Embarcadero måske at skabe en utvetydighed
eller mere sammenhæng i stilguiden ved udelukkende at bruge "Pascal Casing". Indtil da
havde InfixCaps været synonym med Pascal Casing i den originale stilguide.
"InfixCaps" is only mentioned once in the new style guide, and "Camel Casing" is used as
the header for a section explaining the Pascal Case as being a variant of the Camel Case.
While this is true, it may add to the confusion among developers who are not familiar

23
with the fact that Camel Case comes in a lower-case and an upper-case version. To avoid
further confusion, we will only use "Pascal Case" in the manual, which is unique and used
in style guides across programming languages and has the same definition as "Upper
Camel Case". There is no such thing as "lowerPascalCase".

Identifiers
An identifier is any name that identifies an entity. And an entity can be of all kinds, in-
cluding, but not limited to, variables, types, constants, functions, procedures, methods,
properties, units and more. This fact makes the one rule on identifiers a far-reaching rec-
ommendation. In short, an identifier is a programmer-specified word consisting of a text
of alphanumeric characters that must start with an alphabetic character or an underscore.
Names, and compound names, can thus be identifiers, but identifiers do not have to be
names - "I" can, for example, be an identifier, but there is not much "name" in it.
The code snippet below highlights all identifiers with a yellow background. If we also fol-
low the lower-case rule for reserved words (those bold navy words), then we've pretty
much covered everything. We can change colors for identifiers in our IDE under the set-
tings [Tools / Options / User Interface / Editor / Color].
// All identifiers highlighted:
procedure TForm1.FormClick(Sender: TObject);
var
I: Integer;
begin
if Enabled then
for I := 0 to 9 do
Tag := Tag + I;
end;

In Object Pascal, then, an identifier is a representation of a token in words that refers to a


specific entity, consisting of alphanumeric characters that are not case-sensitive. An
identifier can only be used within a scope of their declaration. Wherever we declare an
identifier, the position determines its scope. An identifier declared in a program, function,
or procedure has a scope limited to the block in which it is declared. An identifier declared
in the interface section of a unit has a scope that includes all other units or programs that
refer to the unit in which the declaration occurs.
We distinguish between local identifiers, which are declared in functions and procedures,
as being in a tight scope, and global identifiers, which are declared in a wide scope. When
an identifier is not qualified, the interpretation is determined by the rules for scope.

• Erklæringssektionen af et program, en funktion eller en procedure: Fra erklæring-


spunktet til slutningen af en aktuel blok, inklusive alle blokke, der er indeholdt i
denne scope.
• Interface section of a unit: From the declaration point to the end of a unit and to all
units or programs that refer to this unit.

24
• Implementation section of a unit, but not within a block of a function or proce-
dure: From the point of declaration to the end of the unit and available to all func-
tions or procedures in that unit, including the initialization and finalization sec-
tions, if any.
• Type definition of a record: From the declaration point to the end of the definition
of a record.
• Type definition of a class: From the point of declaration to the end of the defini-
tion, including the descendants of a class and the blocks of all methods of the class
and its descendants.

Enclosed blocks are also called inner blocks, and enclosing blocks are also called outer
blocks. Any redeclared identifier in an inner block takes precedence over declared identifi-
ers in an outer block. Understanding the rules of scope is critical to how we name identifi-
ers meaningfully and how we use the same name for multiple identifiers in different units
without introducing confusion or conflicts. Therefore, it is possible to reuse the same
name for an identifier, but not in the same block. And we can qualify an identifier to re-
solve name conflicts, but only from the innermost blocks to the outermost blocks, e.g.:
// Valid (in a unit named Unit1.pas)
var
I: Integer;
procedure DoSomething;
var
I: Integer;
begin
I := Unit1.I;
end;

// Invalid
procedure DoSomething;
var
I: Integer;
begin
I := 0;
var I: Integer;
I := 0;
end;

The scope of identifiers affects naming conventions and controlling the scope of identifi-
ers must prevent misleading references and name inconsistencies. The order of units in
uses clauses also determines which identifiers are referred to if two or more identifiers
have the same name but declared in different units. This also means that an identifier can
shadow another identifier with the same name.

Pascal Case
A clear and visual difference in language-specific naming conventions is often the styliza-
tion, or casing, of letters. And unlike the Object Pascal Style Guide, other language style

25
guides may use a mix of rules depending on the type of identifier we're working with. And
as already mentioned, most style guides will consider acronyms and abbreviations in
identifiers bad practice, unless they are widely used, e.g., HTML, URL, etc., and therefore
style guides can also contain rules about abbreviations and acronyms.
Examples with identifiers and Pascal Case with type and declaration:
type
// Class name
TMIDIMessage = class(TObject)
private
// Private field variable
FStatus: Byte;
// Method and argument
procedure SetStatus(const Value: Byte);
public
// Abbreviation, acronyms, and Winapi.MMSystem identifier
function SendMIDIMsg(DeviceID: LongWord): MMRESULT;
// Property identifier
property Status: Byte read FStatus write SetStatus;
...
var
LValue: Integer; // Local variable

There are a few developers who would like to give the impression that (lower) camel case
is becoming more and more widespread in Object Pascal. However, it contrasts some-
what with a greater popularity of Pascal Casing in other modern languages, such as C#.
The perception may well come from open groups and little familiarity with the Object
Pascal language and may be encouraged by naming conventions intended for other lan-
guages, or simply inspired by the lower camel casing prevalent in Windows API libraries,
or the overwhelming use of prefixes in style guides for e.g., Visual Basic.
The most widely used style guides for Object Pascal highlight Pascal Case, and we can as-
sume that this circumstance may have been a topic during the compilation of the new
style guide, now that terms like InfixCaps and Camel Case have changed. However, all ex-
amples in the new style guide are still written in Pascal Case for all identifiers.
If you appreciated the book "Clean Code", you will also recognize that the first general rule
is to follow a standard convention. And you will also have noticed that examples in the
book follow a standard convention for Java. This might have led to a common
assumption for some that lower camel case was the same as Clean Code. Of course, that's
not true. Leaving aside the coding style for Java, the principles behind Clean Code are
worth reading. The principles are not restricted to Java, and apart from rules for
stylization, the principles can be applied to virtually all programming languages.
The recommended rule for stylization in the new style guide is Pascal Case. And for an
identifier to conform to Pascal Case, it means that the first letter of any word, compound
or not, abbreviation or acronym, should be capitalized, like in below example for private
field variables:

26
FValue: Integer; // Correct
fValue: Integer; // Incorrect

Pascal Case is a naming convention in which the first letter of each compound word of an
identifier is capitalized. Subsequent letters of a word must be lowercase regardless of what
they may have been in ordinary language. This means that "upper camel case" will be
"UpperCamelCase" and "McDonald's App" will be "McdonaldsApp".
// Examples of correlating identifiers:
FVisible: Boolean;
procedure SetVisible(Value: Boolean);
property Visible: Boolean read FVisible write SetVisible;
// Examples of good method identifiers:
procedure DisableControls;
procedure EnableControls;
// Examples of bad method identifiers:
procedure DisCtls;
procedure EnCtls;

It is important to emphasize that none of the variants for camel casing have rules that
specifically require lowercase letters for subsequent characters, but that this is a conse-
quence of the fact that we must distinguish between each compound word with a capital
letter. Just as none of the camel casing variants have rules that specify that acronyms
must be written in lowercase letters. Each letter in an acronym actually represents a word
and should therefore be capitalized. But either approach will introduce a jumble of quirks.
In the original Object Pascal Style Guide, the Pascal Case rule for all identifiers was fol-
lowed up with an additional rule for acronyms only, that all embedded acronyms should
be capitalized. This rule is completely omitted in the new style guide, and this matter will
be described in detail in the next section on acronyms.
A fundamental omission of the Pascal Case rule applies to references of identifiers that
have already been declared. We are thus not forced to comply with the rule, but simply
refer to the name as it is stylized and respect the stylization. We can find plenty of exam-
ples from the frameworks supplied with Delphi, and from especially in the large amount
of header files for Windows APIs. We refer, for example, not to MIDIOutOpen with Pas-
cal Casing, but recognizes the stylization of midiOutOpen, thus also increasing the rec-
ognizability of the frameworks used in the source code.
if midiOutOpen(FHandle, ... // Correct
if MIDIOutOpen(FHandle, ... // Incorrect

Windows has been developed over several decades and continues to change, so the envi-
ronment today is created with a mix of many rules. As examples, we can mention the
HtmlHelpA function from the htmlhelp.h file and the IHTMLDocument2 interface.
There have clearly been different rules at play in the stylization of names for methods,
files, interfaces and other things. And that way we get even more mixed signals when we
look at methods like midiOutOpen from the file mmeapi.h. HTML is a familiar

27
acronym, and so is MIDI. The difference may be for historical reasons, but it shows that
different rules have been used for the stylization of identifiers from project to project and
over a longer period.
For languages like C#, the rules for identifiers are more explicit; use Pascal Casing when
we name a class, record, struct, interface and public members of various types, such as
fields, properties, events, methods and local functions, as well as positional records; and
only then use lower camel case when naming private and internal fields and for parame-
ter names in methods. Perhaps not so surprising when Anders Hejlsberg is a key figure in
the C# language design team at Microsoft and was Chief Architect for Delphi at Borland.
It is reasonable to believe that he had a hand in the construction of both style guides.
The point is that units in Delphi, e.g., Winapi.MMSystem.pas, consisting of declarations
with APIs for winmm.dll, as well as Winapi.Windows.pas, with APIs for hhctrl.ocx, rec-
ognize the stylization of identifiers already declared in the respective frameworks, and re-
fers to functions as stylized in midiOutOpen and HtmlHelpA. We should not refer to
identifiers by changing their styling just to satisfy our code style preferences.

Scope of Enumerators
Leaving aside identifiers that have already been declared, we have of course noticed that
the only exception to the Pascal Case rule applies to constants (or enumerators) of an
enumeration. Before we move on to acronyms and abbreviations, we can add a few re-
marks about this exception. Before scoped enumerations were introduced, we used con-
stants of an enumeration with a prefix, e.g., fsBold enumerator in TFontStyle that is liter-
ally a global constant. And this is a problem in Object Pascal that gave rise to the excep-
tion to the Pascal Case rule for all identifiers.
The syntax for declaring enumerations has not changed, and the primary reason may be
compatibility. And we can only get scoped enumerations by explicitly using a compiler di-
rective. The directive is a switch and can be used on a single declaration of an enumera-
tion by turning it off immediately after, or it can be used for an entire unit, or just until we
turn it off. The directive cannot be used globally for a project.
In newer languages like C#, an enumeration is at least scoped to the same level as its own
scope. C++, like Object Pascal, only had unscoped constants before the C++11 standard,
but unlike Object Pascal and a compiler directive, improvements were added to the C++
language itself. An improvement to the Object Pascal language might have been more at-
tractive, since compiler directives often involve annoyances. Below is a small detail that
makes the difference between scoped and unscoped enumerations in C++.

28
enum MIDIMessageTypes
{
...
// vs.
enum class MIDIMessageTypes
{
...

With each new version of Delphi that is released, we see an increasing use of the new di-
rective in new declarations of enumerations, while keeping the old declarations of enu-
merations as is. The new declarations have mainly been achieved in two ways; either the
directive is used on an entire unit at the top of the file, or it is used locally on a single dec-
laration. The latter is often used to declare enumerations in a class in older units such as
in the VCL library, as the first approach will break compatibility.
One purpose of declaring identifiers inside a definition of a class is of course to make a
declaration a scope of that class, but without the compiler directive the scope of the decla-
ration will be global, although the actual declaration is positioned inside a class. The com-
piler directive must be used to make the scope work as intended, regardless of whether a
location might resemble an enclosed scope. And since the scope of identifiers is prefera-
ble, also according to Coding Best Practices, and global constants are seen as bad practice,
we should also have an attitude towards a more consistent use of scoped enumerations.
And the easiest approach is to continuously add the compiler directive at the top of each
unit that we add to a project. In the same way that new files are added to Delphi's library.
// Recommended
interface

{$SCOPEDENUMS ON}

type
TMIDIMessageType = (Voice, System, RealTime);
TMIDIMessage = class(TObject)
public type
TVoiceType = (NoteOff, NoteOn, PolyKeyPressure,
ControllerChange, ProgramChange,
ChannelPressure, PitchBend);
...

// Recommended for targeting single declarations


{$SCOPEDENUMS ON}
TMIDIMessageType = (Voice, System, RealTime);
{$SCOPEDENUMS OFF}

// Not recommended for unscoped enums


TMIDIMessageType = (Voice, System, RealTime);

// Correct for unscoped enums, but not recommended


TMIDIMessageType = (mtVoice, mtSystem, mtRealTime);

29
The new style guide recommends using enumerations with scope unless it affects librar-
ies that already require backward compatibility. The above recommended declaration of
enumerations will result in the following code construction:
function TMIDIMessage.IsVoice: Boolean;
begin
Result := FMessageType = TMIDIMessageType.Voice;
end;

If you use Delphi's Code Formatter, you'll notice that it formats names with first letter in
uppercase regardless of whether they're enumerators already declared elsewhere and styl-
ized as lowercase in a prefix.

Acronyms and Abbreviations


Some style guides have strict rules for capitalization of acronyms and abbreviations.
Some will require that the first letter must be capitalized, and all subsequent letters must
be lowercase, e.g., "Midi". Exceptions to this rule can be acronyms with only one or two
letters, e.g., "ID". Few other style guides can have even stricter rules for how each letter
should be capitalized.
The original Object Pascal Style Guide had a rule for capitalizing each letter embedded in
an acronym, e.g., "MIDI" and not "Midi". The rule has been omitted in the new style
guide, and acronyms must now follow the general rule of Pascal Casing. Neither Pascal
Casing nor Lower Camel Case has clarifications in the capitalization of acronyms, and
therefore a style guide takes a traditional position on how acronyms should be capitalized.
By omitting the original rule about acronyms, and not replacing it with another rule, we
make the new style guide more lenient towards either "MIDI" or "Midi". Most naming
conventions that incorporate Pascal Casing will expect only the first letter of an acronym
of more than two letters to be capitalized, e.g., "Midi". This is the most common under-
standing and practice of Pascal Casing for acronyms.
A strict enforcement of one of the two types in the stylization of acronyms is often ignored
by developers because it often involves a lot of hassle with "irregularities" in acronyms.
We can easily imagine some ridiculous names if we, for example, had to develop a frame-
work for network monitoring, and had to make use of Cisco IOS (Internetworking Oper-
ating System) APIs and had to support the Apple iOS (iPhone Operating System) plat-
form among others. And we choose to call our framework "Ios" - after a Greek island. Del-
phi is named after a city in ancient Greece, so why not?
The formal practice of stylizing letters is called "medial capitals" and is used when com-
posing words or fragments of words, and simply means that a capital letter may appear
roughly in the middle of a word, but that we already have an expectation of capital letters
as the first. The principle is also used conventionally in abbreviations to reflect the styliza-
tion that the words would have when written out in full. It paved, among other things, the
way of notations such as the Hill system, e.g., formulas such as "NaCl" that can be

30
understood without ambiguity. However, discussions among professionals suggest that
medial capitals are not so equal when we, for example, can't decide on "MIDI" or "Midi".
Indeed, even with the principles of medial capitals, all types of acronyms will exceed the
rationale for using a "one size fits all" approach. Wikipedia compares at least 11 types of
acronyms, not counting notation systems, or stylization in names like "McDonald" and in
academic titles like "PhD". The large number of types for acronyms has been used to
demonstrate the weakness of strict rules in the stylization of identifiers.
When all identifiers must follow the general rule of Pascal Casing, and no rules for acro-
nyms are specified, then the main rule becomes quite forgiving by recognizing several
stylizations of MIDI, e.g., "Midi" or "MIDI". The former might be easier to read for one
group of developers, while the latter respects the MIDI Association's official trademark,
and perhaps more easily recognizable to professionals with a musical-technical back-
ground. Although both would conform to Pascal Casing, uppercase is still the prevailing
capitalization in the Object Pascal language for most common types of identifiers with ac-
ronyms.
Another reason to choose a particular capitalization, "MIDI" or "Midi", would be how it is
used in the real world. The acronym is stylized as "MIDI" in the musical industry, and
therefore it would also weigh more heavily in favor of "MIDI", since the entire standard
specification is consistent in the stylization of "MIDI", also in the technical documentation
of the MMA (MIDI Manufactorers Association) . It can also solve some challenges with
naming identifiers such as iOS, IOS and our famous Ios framework.
The MIDI specification also has explicit requirements for the styling of labels for MIDI
ports and other things, e.g., "MIDI OUT", and such requirements can also play a role in
the stylization of identifiers in many industries. But it will also raise more questions than
answers, because "out" in "MIDI OUT" is an abbreviation of "output". Therefore, there are
many aspects that play together or against each other when we have to choose the capi-
talization of an abbreviation or acronym. For each acronym embedded in identifiers, e.g.,
MIDIInDevice or MidiInDevice, then we should especially ensure consistency
throughout the use of the acronym in other names, e.g., MIDIOutDevice or Midi-
OutDevice, MIDIThruDevice or MidiThruDevice. Not just in a scope of a class,
but also across a project or framework.
// Correct
TMIDIInDevice = class(TMIDIDevice);
TMIDIOutDevice = class(TMIDIDevice);

// Correct
TMidiInputDevice = class(TMidiDevice);
TMidiOutputDevice = class(TMidiDevice);

// Incorrect
TMidiInDevice = class(TMIDIDevice);
TMIDIOutDevice = class(TMidiDevice);

31
It is no accident that the "MIDI" acronym is used in the examples, because the technology
standard uses large amounts of other acronyms and abbreviations. Furthermore, imple-
mentation of the MIDI standard includes precise requirements for marking physical con-
nectors, e.g., "MIDI OUT", but also for logo stylization before we are even allowed to use
the MIDI logo in our products. It is not unusual to use a standard style guide and a for-
malization of acronyms specific to an industry. If we simply referred to some few varia-
bles for a MIDI device, which necessarily did not accommodate the development of an
entire framework with MIDI technology, then we would probably have had a different
approach.
When it comes to acronyms, we just have to be pragmatic and still follow the general rule
for the other compound words for an identifier. There is no one rule that fits all types of
abbreviations and acronyms. This is probably also the reason why in Coding Best Prac-
tices it is recommended to avoid acronyms and especially abbreviations. It just has to be
said that the latter is almost an impossibility. However, a general rule for all abbreviations
and acronyms should be readability and recognizability rather than strict rules for the
stylization of the individual letters.
After decades of working with MIDI APIs on various platforms, I can easily recognize
midiOutOpen in a code construct as an API call to Windows Multimedia technology. If
the reference was stylized as MIDIOutOpen, which by the way is a completely legitimate
reference to the same API function, then I would probably raise one eyebrow and con-
sider whether this was intended for another call. I'll probably find out that it's the same
call, even though I've wasted some time, but the problem is clearly the short moment
when doubt arises - stylization can be ambiguous.
And similarly, if a reference to a related API call in the MacOS Core MIDI framework,
MIDIOutputPortCreate, was stylized to match other rules, e.g., midiOutput-
PortCreate, then the name will lose some recognizable traits from that particular
framework. These are plain examples but changes in stylization can cause confusion or
misunderstanding if we remove some traits of an identifier that others can recognize.
You'll have noticed, of course, that Apple's Core MIDI framework has used acronyms styl-
ized entirely in capital letters and Pascal Casing for compound words. This does not apply
to all their frameworks. As on the Windows platform, we will see characteristics in differ-
ent rules over time, and perhaps a manifestation of the programming language used be-
hind the APIs and the paradigms that have been applied.
What we should note and remember before closing the topic of acronyms is that we will
find stylization and a capitalization rule that is consistent throughout an entire framework
or project, but not necessarily across all frameworks or projects from the same company,
platform, or technology.

32
Keywords
The second general rule is applied to keywords, and these are words that are very easy to
distinguish from the rest of the code, because the words are stylized with a bold font as
default, e.g., procedure begin end. And the rule is also easy to follow because keywords,
reserved words and context-sensitive directives should all stylized with lowercase letters.
There is a small error in the new style guide, as "compiler directives" are mistaken for
"context-sensetive directives", and the difference between the two is quite significant. It's
a "typo" that can be a serious setback for anyone who wants to enforce the style guide or
is just starting to learn the style. Compiler directives, e.g. {$SCOPEDENUMS ON}, are
generally all capitalized. Keep this in mind before we ask anyone to use lowercase letters
for compiler directives. Compiler directives are easy to distinguish from keywords, as by
default they are stylized with a green font color and not bold or italic.
Although in the manual we refer to them as "keywords", also because they are stylized in
the same way, and most developers, like in the Delphi documentation, do not distinguish
between the term "keyword" and "reserved word", there is a slight difference on the two
terms. A reserved word cannot be used as an identifier because the word is part of the
language syntax, e.g., begin, if, then, else, end, etc. Keywords are closely related to
reserved words, but only have special meanings in a specific context, and can thus be in-
terpreted as identifiers elsewhere.
As for most concepts, their formal use changes from language to language, so we must
not confuse it with a general interpretation of the term keyword. The Delphi documenta-
tion lists some keywords (in the usual meaning) as context-sensitive directives and
should not be confused with compiler directives. Perhaps "context-sensitive keywords"
could also have been less confusing for people at Embarcadero, but they probably also
had other considerations.
Context-sensitive directives act like keywords, and a few were also previously referred to
as scoping directives in the early years of Object Pascal. Scoping directives is comprised of
the four original access specifiers, private, protected, public, and published, and are in-
tended to limit declarations in their scope under a type definition of a class. Scoping direc-
tives are basically the same as access specifiers, which is the term used in the object-ori-
ented paradigm. As the language evolved and more directives were added, the term
"scoping" became out of place, and was then replaced by the term context-sensitive direc-
tives.
The term "access specifier" is introduced in the new style guide together with the term
"context-sensitive directive". The first term replaces the term "scoping directive", and the
last term is not a commonly known term in programming languages but has the same
meaning as "context-sensitive keyword"; a more commonly used term in other program-
ming languages.

33
Indentation
The third general rule in the new style guide is about indentation, which, however, is only
mentioned as a basic indent of two spaces and no tabs. Indentation and white space do
not affect the function of a code, but consistent indentation makes the code more reada-
ble. When and how to break a line and, e.g., indent continuation lines, has been moved to
the "Type Declaration" chapter.
Like most programming languages, the idea behind indentation is to break up code con-
structs into blocks. Object Pascal is a free-form language, so it is possible to obfuscate
code and make it completely unreadable, thereby forcing severe mental mapping on any-
one trying to understand the code.
// Random white space and indentation, and case-insensitive
fUnCtIoN UpPeRCaSe(CoNsT S:sTrInG;a:tlOcalEOPtIOns):StRiNg;bEgIn If
a=lOuSerlOcale tHeN rEsULt:=aNSiuPPercASe(s)ElSe ReSUlT :=
uPpErCaSe(S);eNd;

The above function Uppercase is from the System.SysUtils unit, it compiles without
warnings or hints, and works as intended, as well as not breaking code that references the
function. Below is the original function reproduced, with recommended indentation (and
stylization) that makes it more readable and review-friendly for other developers.
// Correct indentation and white spaces
function UpperCase(const S: string; LocaleOptions: TLocaleOptions): string;
begin
if LocaleOptions = loUserLocale then
Result := AnsiUpperCase(S)
else
Result := UpperCase(S);
end;

Today, most programming tools have functions that do the most basic work of indenting
lines of code, and the best tools also help us position the cursor, insert keywords, format,
and indent, all while writing the code. Since Object Pascal is a free-form language, inden-
tation is optional, and indentation rules are only to increase readability. Basically, the in-
dentation should visualize blocks of code and help us create an overview of which blocks
are executed at a given time.
Modern development tools also offer to highlight blocks of code, either with colored lines
or by changing the background color of a block. Older versions of editors highlighted
blocks of code simply by counting the indentation of a line. Today, advanced editors parse
code constructs to highlight an exact block of code, perhaps at the expense of perfor-
mance. Other editors also offer plugins that can allow us to define ourselves how code
blocks should be highlighted.
Standard highlighting of code blocks in recent Delphi versions is called Structural High-
lighting and highlights blocks using lines from the beginning of a block to the end of a
block, aligning the line against the inner indentation of the code block. Usually, we will

34
need syntax words like begin and end or case constructs to trigger the highlighting.
Blocks that only consist of a single line, e.g., after an if condition, are not highlighted re-
gardless of their indentation.
Regardless of the tool used to highlight code blocks, indenting code constructs in blocks
should still be paramount with a focus on readability, because the same tool is unlikely to
follow through after a commit and code-review. Test developers, quality assurance, or a
security test of code and security approvals with third parties, probably use some other
completely different tools.

White Spaces
A free-form language like Object Pascal would consider multiple white spaces as a single
space (not those in quotation marks) or a blank line. Excessive use of white spaces is con-
sidered noise, as opposed to a normal practice that would increase readability. Visually,
we consider the character for spaces and blank lines as white spaces, but we can easily
find a technical definition of what the compiler will consider a white space. Like the style
guide, we just see spaces and blank lines as the two types of white spaces.
// Random white spaces
function UpperCase(const S:string;LocaleOptions:TLocaleOptions) : string;

begin
if LocaleOptions=loUserLocale then
Result := AnsiUpperCase( S )

else
Result := UpperCase ( S );
end;

The new style guide has a list of how white spaces should be used and a list of how white
spaces should not be used. The style guide comes with a few examples of correct and in-
correct use of a white space. We have a few examples of code with correct and incorrect
use of white spaces on the previous page, and above is an example of the same code with
incorrect use of white spaces. In what follows, the word "spaces" is used, and later "blank
lines", instead of white spaces.
The first rule of how spaces should be used is around operators. The most interesting op-
erators are the arithmetic operators such as +, -, * and /, but also include div and mod.
We also often use the Boolean operators in expressions, e.g., not, and, or, and xor. The
fact that operators also include words like "div" makes it difficult to apply the "no spaces
between operators" rule when the compiler will necessarily depend on a space around
"and" in order to compile.
The spacing rule generally follows the common operator spacing in mathematical expres-
sions, making the spacing rule around operators in Object Pascal easier to understand, for
example:

35
// Correct
if (A > 0) and (B > 0) and not (A^2 + B^2 = C^2) then
C := Sqrt(A^2 + B^2);
// Incorrect
if (A>0)and(B>0)and not(A^2+B^2=C^2) then
C:=Sqrt(A^2+B^2);

Boolean expressions with many operators are common in code, and a consistent style
makes constructions with many conditions easier to read. Do we work, e.g., with mathe-
matics and have a need to express ourselves mathematically, then we are not constrained
by the rule either. We are welcome to use rules that are more appropriate to our needs,
but we should do so consistently and formally.
The following three rules are basically identical and state that a space must be used after a
comma that separates generic types and parameters for methods, including also after a
semicolon. The remaining rules about where spaces should not be used could have been
clarified by a few general rules rather than trying to list all constructions where it should
not be used.

• Spaces should not appear after an opening parenthesis and before an ending pa-
renthesis.
• Spaces should not be used between an identifier and its opening parenthesis and
after an ending parenthesis, unless followed by an arithmetic operator.
• Spaces should not be used before a colon for a statement, nor before a semicolon.

36
Chapter 5
Descriptive
and Meaningful
We have already been through an important part of a naming convention in the previous
chapter, which is the stylization of letters, and another important part of conventions is
working with descriptive and meaningful identifiers. Although the new Object Pascal
Style Guide only mentions the recommendation as a general rule about descriptive names
in the chapter on "General Rules", the issue is actually far more important and compre-
hensive than a small side note.
It is quite reasonable to focus the discussion of the two general rules in naming conven-
tions separately, i.e., rules for stylization of letters and the recommendation for descrip-
tive and meaningful names, as each rule can be used in different style guides inde-
pendently of each other. In short, descriptive names do not depend on a rule of styliza-
tion, because SetPosition will be as descriptive as setPosition, and meaningful-
ness will depend on context.
It is important to explore the idea of the descriptiveness in identifiers and what makes an
identifier meaningful in different contexts. Here, a style guide will formalize our
expectations and promote consistency in teams, which in turn improves the professional

Image by xkcd.com, and licensed under a Creative Commons Attribution-NonCom-


mercial 2.5 License.

37
presentation of software code. Following a naming convention is considered Coding Best
Practice, not least because it should make code more readable. With conventions for most
programming languages and dialects, it is therefore important to consider wisely before
we start enforcing a specific convention.
Regardless of whether we are into Clean Code and the like, it is important to respect the
professional approach and the benefits of being consistent, which is achieved by following
a standard or a de facto standard convention for a specific programming language, here
the Object Pascal Style Guide for Delphi from Embarcadero, and not a modified version
of, i.e., a C# convention. Likewise, C# professionals won't be terribly excited about a cus-
tomized Object Pascal Style Guide for their C# project.
Almost all style guides recommend meaningful or descriptive names, imperative verbs in
method names, etc. But style guides rarely go into detail about how we create meaningful
and descriptive names and what makes a name meaningful or descriptive. Here we need
to resort to other sources like Clean Code and similar concepts of Coding Best Practices in
naming identifiers to get an idea of meaningful and descriptive names that give an identi-
fier the ability to communicate to us what it is and do. Up until now, we have emphasized
the importance of naming for a few reasons:
1) It eases the work of reading and understanding source code, and
2) code reviews can focus on logic rather than syntax and naming.

Naming identifiers is a difficult exercise, and we often adjust names during the design of
classes and during the construction of code. Over time, some names can become difficult
to change, especially once published and in use, but also in cases where names become
critical and constrained by compatibility requirements. Some studies suggest that less
than 10% of developers will choose the same name for the same task, so the likelihood of
misinterpreting a name should be high.
On the contrary, the same studies show that a name is understood by most developers
once it is chosen – usually. It is the large number of identifiers, which constitute about
two-thirds of all characters in a source code, that greatly increases the probability of mis-
interpreting a couple of identifiers. Just a few misinterpretations can easily turn out to be
disastrous for a small task or an entire system.
Other studies show that identifiers can be up to 32 characters long before perhaps becom-
ing a bit too descriptive. Names longer than 32 characters prove difficult to read, and the
32-character maximum name limit should be sufficient in most situations when scope
and qualification of names are considered, for example:

38
1) A little too long:
TListOfMusicalInstrumentDigitalInterfaceSystemExclusiveMessages
2) Maximum suggested length:
TMIDISystemExclusiveMessageItems = class(TMIDIMessageItems)
3) Typical length and names of the above MIDI classes:
TMIDISysExMessages = class(TMIDIMessages)
4) A little too short:
TMSEMsgs = class(TMMsgs)

Very few style guides have definite rules for the length of identifiers, but regardless of this,
we should aim for clarity to be more important than length, just as readability is better
than brevity. When names for identifiers get a little too long, it might be time to consider
a redesign of the construct, in the same way that we would consider reconstructing code
with too many lines and perhaps too many declarations of variables.

Descriptive Names
The new style guide uses the term "descriptive", and in other style guides or Best Prac-
tices we can also find the term "meaningful". Both terms go hand in hand, as in "Descrip-
tive and Meaningful Phrases" (DAMP), popular among test developers. Being "descrip-
tive" without any explanation of what it means is almost an invitation for discussions, but
the point is that an identifier should reveal its intent, and ultimately help understand the
meaning. The intent should suggest why it is there, what it does, and how it will be used.
It's not about identifiers that consist of some elegant passages in their names, but rather
names that are unambiguously understood by developers. It is quite clear that the Set-
Position method from TTrackBar will set the current position of a thumb to match a
numeric value that is supplied as an argument in the call.
As in the original style guide, the new style guide offers only a few examples with good
and bad names. They do not describe anything about what constitutes a descriptive
name. An example of a good method name is DrawCircle and is an imperative verb,
and another example of a bad method name is drawCircle. Both names are equally de-
scriptive and only a rule of capitalization differs. That something is descriptive thus has
little to do with rules about casing.
We can construct the following example with two logically identical lines of code and
agree that there is a big difference in their visual expression:
t := g - n;
and
Tare := Gross - Net;

Each identifier in the latter line of code is more descriptive than its counterpart in the first
line of code, making the latter code much more readable and understandable. The

39
identifiers are not only more descriptive; the entire line of code also reveals its intention.
And without the last example, we probably wouldn't have been able to figure out what the
idea was with the first example, except that it subtracts one number from another, but
why?
We can construct another example and agree that the following is highly readable for
most people:
if road is not blocked then go straight else turn around.

And except for some symbols and syntax, the above could almost compile. And with
structuring, it will also come very close to pseudocode. Of course, it is not as easy with
identifiers, but readability is about getting as close to how we read as possible. The above
sentence could easily be translated to:
var
a: TDrvAct;
begin
if st <> rsBlckd then
a := daStrght
else
a := daTrnBck;
The constructed code is nowhere to be found in real life, and it would be a coincidence if it
truly existed at all. But the point of slightly more descriptive identifiers is highlighted be-
low with the same code:
var
Action: TDrivingAction;
begin
if FRoad.State <> TRoadStates.Blocked then
Action := TDrivingAction.GoStraight
else
Action := TDrivingAction.TurnAround;
It is similarly possible to get closer to code that is more readable without changing the
logic and process at all. This, among other things, makes Refactoring an obvious ap-
proach to make a construction more readable and bring the code up to a higher level.
Other approaches even go further and suggest changing the very logic of a construct if it
can result in a more readable construct. Of course, it should be balanced against the con-
text of a code, and possibly requirements for performance and other regulations, etc., just
as changes to logic could trigger requirements for new tests. In this way, the above con-
struction can, in the same respect, e.g., written completely differently:

40
const
CAct: array[False..True] of TDrvAct =
(daStrght, daTrnBck);
var
a: TDrvAct;
begin
a := CAct[st = rsBlckd];
There is nothing wrong with the last example because it gives the same result, and it may
have been written with performance in mind. Still, such a construction may seem like a
odd approach to some developers, especially if the construction is written with meaning-
less identifiers and the whole construction became incomprehensible. Therefore, descrip-
tive names in code constructs are necessary if they are to be considered readable by us.
This is not the same as saying that a descriptive name is also a meaningful name. On the
contrary, we can make descriptive names completely meaningless.
The last example can be made a little more descriptive, and make a little more sense:
const
CActions: array[Boolean] of TDrivingAction =
(TDrivingAction.GoStraight, TDrivingAction.TurnAround);
var
Action: TDrivingAction;
begin
Action := CActions[FRoad.State = TRoadStates.Blocked];

Meaningful Names
If a name does not make sense in a context, e.g., if we replaced the previously mentioned
Action with SizeOfWaist, then that name becomes completely and utterly meaning-
less, no matter how descriptive that name might be. A local variable named "I", which will
not be objectively descriptive, could easily be meaningful if it were a local variable used in
a loop.
We could write an entire software system to keep track of cars with code constructed
from identifiers meant to keep track of cats, e.g., using CatRace instead of CarModel,
etc. We could remove technical terms for cars and traffic, and only use terms from the bi-
ology of cats and animals in the source code. The only exception would be the captions
used for user interfaces so that the system would make sense to the users of the system.
There is no technical limitation that this could not be done by making this a rule for a
project. All identifiers could easily be descriptive, but the source code wouldn't make
sense, and all developers who maintain the system should probably have access to some
therapy now and then. The system would work as intended, but it would require enor-
mous and constant mental mapping for developers to understand the system.

41
The above notion is completely up in the air, but once in a while the meaning is more ob-
vious when we turn everything upside down. Therefore, the use of a descriptive identifier
must be meaningful in extension of its context, which would make identifiers like Temp
or Ninja quite meaningless, for example:
// Meaningless local identifier
function DayPassed(const FromDate, ToDate: TTimeDate): Boolean;
var
Ninja: Integer; // Name has no relation to the function
begin
Ninja := DaysBetween(FromDate, ToDate);
Result := Ninja > 0;
end;

// Meaningful local identifier


function DayPassed(const FromDate, ToDate: TTimeDate): Boolean;
var
NumberOfDays: Integer;
begin
NumberOfDays := DaysBetween(FromDate, ToDate);
Result := NumberOfDays > 0;
end;
In that respect, it's easy to understand how we make identifiers descriptive and meaning-
ful, but the main purpose of the recommendation is to make identifiers descriptive and
meaningful to anyone other than the original developer of the code. Even the original de-
veloper may wonder about his or her own identifiers with "intentionless" names a few
years down the road when a few changes need to be made.

Recognizable Identifiers
Another aspect of naming conventions that most conventions neglect to highlight as an
advantage is the recognizability of distinctive names. Recognizability is also a common
and strong feature of Software Design Patterns, as implied by the word "patterns". Design
Patterns are also considered Coding Best Practice and worth studying. Here we can also
mention a book like "Code Complete", by Steve McConnell, which inappropriately has a
somewhat lax relationship with style guides, which are based on personal preferences,
but gives a nice overview of many of the common Design Patterns.
If we add a few methods, such as RegisterObserver/UnregisterObserver and
NotifyObservers, to a class, many of us will instantly recognize these names as being
part of a very specific Design Pattern. We could be stupid and construct code with the
same names completely unrelated to the very same Pattern, thus adding nothing but con-
fusion to other developers. And equally, an implementation of such an Observer Pattern
with slightly more challenging method names like AddToList/RmvFromList and
MsgList would deprive developers of the opportunity to quickly understand the idea

42
behind an implementation. The "words" we will hear behind the door at reviews will most
often be "WTF...". In this way, bad practices are also known to increase tensions in teams.
Recognizability even goes across languages and rules for stylization, e.g., registerOb-
server, RegisterObserver and register_observer are all equally recognizable
to a developer regardless of programming language and capitalization rules. All studies
on programming through empirical observation show that a correct name of an identifier
has a great influence on the understanding and maintenance of a software. Research also
reveals that identifiers are a central source of information, where even the semantics of
identifiers can lead to reasoning. And not just recognize every compound word in an
identifier but recognize how an identifier will be used in different contexts.
// Recognizable
TMIDIDevice = class(TObject)
protected
FObservers: TDeviceObservers;
procedure NotifyObservers(const AEvent: TDeviceEvent); virtual;
public
procedure RegisterObserver(const AObserver: IDeviceObserver);
procedure UnregisterObserver(const AObserver: IDeviceObserver);
end;
// Unrecognizable
TMIDIDevice = class(TObject)
protected
FCallbacks: TList;
procedure MsgList(const Event: TDevEvent); virtual;
public
procedure AddToList(const Callback: IDevCaller);
procedure RmvFromList(const Callback: IDevCaller);
end;
Recognizability of identifiers is also consistent with the recommendations for choosing
words for specific concepts. We have all become familiar with names used in data-aware
components, datasets, queries, etc., when we, for example, have developed database ap-
plications, just as we also become familiar with method names to manipulate lists or
streams. We get used to names like Assign, we know its precise purpose, and its single
responsibility that is linked to a method of that name. If we design a class with a method
with the same responsibility as Assign, but choose to call it Copy, then we have broken
a concept.
If we develop a class with a compound name consisting of "List", e.g., TItemList, which is
not generic or inherited from Tlist, then we expect to find methods that resemble names
associated with a list, e.g., Add, Append, Delete, Insert, IndexOf etc. Otherwise,
the concept of a list as we know it and have become familiar with it will also be broken.

43
Intention Revealing Names
Another reason to recommend meaningful and descriptive identifiers is the idea of names
that can reveal their intentions, or purpose. Shortly said; if we need to comment an iden-
tifier and explain why it's there, what it does, and how it should be used, then we haven't
been good enough to reveal the intent, e.g.:
// The identifier reveals nothing
C: Integer; // Elapsed time in MIDI clocks

// The identifier reveals how many MIDI clocks has elapsed.


MIDIClocksElapsed: Integer;
The latter identifier could be declared in a tight scope, in a method of a MIDI class, to se-
quence MIDI messages, and then perhaps avoid giving the name a prefix (MIDI), since
ClocksElapsed should work satisfactorily. But "MIDI beat clock", or just "MIDI clock",
is the correct name for the clock signal sent with the MIDI protocol, and that way the
name will be tied to the specification in a strong and meaningful way. And because MIDI
Clocks depends on a tempo, we want to avoid the name being confused with elapsed
time, i.e., in hours, minutes and seconds, which is the common understanding of the
word "clock", which can give rise to misunderstandings in that sense.
Names of methods should explain their intent, almost at a level so that non-programmers
will be able to decipher what is going on. However, we must also see the names in the
context in which they are declared before we write long names. The name of the In-
dexOf method might reveal a bit of its intent, and while most developers would recog-
nize the name, a fully qualified identifier for the TStrings.IndexOf method would be
far more revealing.
The context shows another aspect of the research on intention-revealing names. The fact
that not all identifiers need be fully intent-revealing names if they are closely linked to
names that already reveal their intent. Research also shows that a method with an imper-
ative verb like SetPosition does not need to be followed by a parameter named "Posi-
tion", eg:
procedure SetPosition(const APosition: Integer);

The name "SetPosition" reveals an intent, and we expect it to be supplied with a new
value for a position. The intent revealing method is so powerful that most of us don't even
see the name of the parameter. An argument with a new position is expected, so the pa-
rameter can easily be named as:
procedure SetPosition(const Value: Integer);

44
A method should have a name according to what the method does, and the name should
clarify the code. With a good method name, we should feel no need to analyze the code to
understand what the method does or need to comment the method.

Misleading Names
Clean Code enthusiasts will of course emphasize that we must avoid misinformation, i.e.,
that names must not lead us in the wrong direction if we have acquired a different percep-
tion of names. We can imagine if a SetPosition method in a class with a name composed
of the word "Stream" does not set a current position of an index to a buffer in memory to
a new position, but instead sets the buffer's physical position in memory.
Names composed of words like "List" and an identifier that doesn't really represent a list
are also considered misleading and we will misinform other developers. Names such as
l0 (small L and the zero sign) and MID1 should be avoided and can cause confusion in
projects that e.g., make use of some framework. We just shouldn't name a string variable
like StrName that is meant to hold the name of a street either.

Misleading, misinformation or disinformation and the like are simply names that can lead
to misreading, misinterpretation, misunderstandings and confusion. Names can cause us
to break an otherwise perfect design and must make reconstructions because we have
misinterpreted a name. Or "fixing a bug" that just made it worse because we got a name
and its purpose wrong.
Misleading names are in a way closely related to meaningless names, but a misleading
name can easily appear to be both descriptive and meaningful in its context, except that it
can be misinterpreted by developers. A property named AsInteger that returns a value
of type string would be misleading, regardless of whether its contents could be converted
to an integer. A name should not be a contradiction of its intention.
A class inherited from TStrings that contains an XML document as a list of strings would
be misleading if it were named TXMLStream. Or inherited from TStream and called
TXMLStrings. Or worse, a definition of TXMLStrings as an array of strings and we then
prepared for a parser based on TStrings. This type of small misunderstanding is actually
common and perhaps easy to refactor, either by redefining the type or reconstructing the
parser, but we've wasted time on a misunderstanding in what otherwise appeared to be a
minor task, and perhaps ruined a good design, because we are introducing a redesign at
the last minute, as we are still committed to this task only having 10 story points. In this
way, a solution ends up being more fragile than robust.
We should not call a variable NotAString because it must contain a text representation
of an integer and the type of our identifier is a string. We should rather use a name like
Address for an e-mail address, because names must convey correct information and
have a specific meaning as clearly as possible. Or more specifically, names should guide
us all to the right understanding of a code.

45
Noise in Names
Declarations of variables that are not used are both clutter and noise. Compound words
or acronyms in a name, or a so-called encoding that represents meaningless information,
are also considered noise. Before scoped enumerators, we had to prefix the names, and
consequently we continued to introduce noise in the form of purposeless acronyms to dis-
tinguish the individual identifiers from each other for the sake of the compiler, e.g., the
"fs" prefix in font enumerators:
TFontStyle = (fsBold, fsItalic, fsUnderline, fsStrikeOut);

Other types of noise are names that resemble each other, e.g., Date1 and Date2. They
can be distinguished by a compiler but convey nothing meaningful to us. Perhaps
BeginDate and EndDate would be more suitable in that context. Dataset1 and Da-
taset2 are similarly similar, and perhaps SourceDataset and TargetDataset
would make more sense in a construct that needs to copy dataset from one set to another.
Or even Source and Target would suffice in a tight scope as parameter names in a
method responsible for that task. It will be safer and more obvious for us, with those
names, to choose the right set of data to copy from and where we want to copy to.
The before mentioned kind of noise, with a consecutive number in names, e.g., Edit1,
Edit2, Edit3, etc., is the standard naming technique for many IDE tools when drop-
ping components onto forms. Ironically, those names are seen as noise if we don't take
the time to rename the components right away.
Another type of noise is like System Hungarian notation, widely used in Windows APIs,
where the current data type is used as a prefix to names. With an extensive use of APIs in
VCL already from the first version of Delphi, it is not surprising that the notation may
have spread to naming identifiers in Object Pascal, even though that type of notation was
already discouraged in the original style guide. With the notation, we often find "creative"
declarations such as:
var
intUserId: Integer;
strUserName: string;
arrUsers: array of pUser;
Hungarian Notation is deprecated a long time ago and was a practice before we got more
complex types in the form of objects in object-oriented programming. It made sense in
early versions of compilers that had no control over types and often resulted in a runtime
type error or mismatch if a variable was incorrectly referenced. Most modern IDE tools
provide access to immediate information about variable types, and Object Pascal has al-
ways been a so-called strongly typed language, checking types before even linking to an
executable file.

46
Nor will we find examples of Hungarian Notation for object types from sources like Wik-
ipedia. We only find examples of Hungarian Notation for primitive types, e.g., string, in-
teger, byte, etc. The intensive use of Hungarian Notation was advocated by the early and
popular tools like Visual Basic, and their names and prefixes for entities thus became
widely used, especially because Visual Basic was a good beginner's tool.
Hungarian Notation is discouraged in modern languages such as C# and Object Pascal
and is also discouraged by the style guides for C++ of many tone-setting companies such
as Google and Microsoft. Famous figures like Bjarne Stroustrup, the man behind C++,
and Linus Torvalds, the creator of the Linux kernel, including the author of "Clean Code",
will find prefixing the types as a limitation and even "brain damaged", especially when we
should have our thoughts aimed at generic "types" and the principles of object-oriented
programming.
Hungarian Notation is also considered anti-pattern, and for many reasons. The most fa-
mous example that is often highlighted must be PostMessage and the wParam param-
eter of type WPARAM. "w" stands for "word" and represents the natural (native) size of
data that can be handled by a given processor. But in Object Pascal, we know that "word"
is a 16-bit word regardless of processor architecture. This kind of noise creates inconsist-
encies among developers across platforms and messes up the naming and construction of
code that targets multiple platforms.
Other types of noise include unnecessary use of words, e.g., SetThePosition or
SetAPosition, as catchy as they are. SetPosition is, for instance, also more reada-
ble than shorter names, just as each compound word will have a meaning, Set and Posi-
tion. Noise also includes the use of names, at the same time or in the same scope, that
have the same meaning, e.g., UserData and UserInfo, or MemoryPosition,
MemoryIndex and MemoryLocation. It will also say a little about inconsistency in
naming identifiers.
The last type of noise may not be so obvious, but it can be names with too much infor-
mation, for example:
TFontStyle = (FontStyleBold, FontStyleItalic,
FontStyleUnderline, FonstyleStrikeOut);
And
Label1.LabelCanvas.LabelCanvasFont.LabelCanvasFontStyle :=
[TFontStyle.FontStyleBold];
It is not because the names are too long, but because the names consist of redundant
words. With scoped enumerators, the name of the type will be redundant, like all other
scoped definitions of types, because they can be qualified, e.g.:
Label1.Canvas.Font.Style := [TFontStyle.Bold];

47
Of course, you have noticed that the name of the label is left unchanged and thus intro-
ducing a noise. The large number of code samples on the Internet that use the IDE tool's
default naming may obscure that type of noise, so we don't put more into it. In this case,
it will not only be considered noise; it will also make the code appear unfinished and in-
correct.
It might also come as a surprise to many, but naming conventions usually focus only on
naming field variables, local variables and other identifiers that make up a code construct.
Conventions are rarely concise in the formal naming of components on forms, so devel-
opers tend to find inspiration elsewhere. Given that prefixing or suffixing identifiers with
type information of a variable is considered noise, it might seem strange if we were to rec-
ommend type information for a class composed to names for components, e.g., Cancel-
Button of TButton class.

But unlike primitive types, e.g., Integer, classes consist of complex types and would al-
ready be constructed by intention-revealing names and following Coding Best Practices
and be descriptive following a style guide, with both meaning, purpose, behavior and re-
sponsibility. TButton is a class; the word is short but descriptive and meaningful, and we
know its intent and function, so an instance of a TButton named CancelButton would
be an even more intention-revealing name. Naming components has its own separate
section later in this chapter.
By comparison, "CancelInteger", as the name of a primitive type, would have little or no
meaning, and might just be confusing. This is the most obvious difference between primi-
tive types and complex types like objects when it comes to naming.

Pronounceable Names
Names for methods like SetPosition have compound words that are not only pro-
nounceable, but also pronounced in a correct disposition. Correct names are therefore not
about spelling all words completely and correctly and avoiding abbreviations of words –
it is largely about pronouncing all compound words as naturally and correctly as possible.
Names such as lblUser, btnCancel, intId, PositionSet, ButtonLookup,
UserNameUpdate and the like are either not very catchy or are a compound name that
is pronounced haphazardly. It's not btnCancel or ButtonCancel, and it's not Can-
celBtn, but simply CancelButton. We must ignore the fact that "button" could have
been mistakenly considered noise, but there is more on that topic in the last section of this
chapter.
In addition to reading names naturally, and without us having to mentally map out all
possible acronyms and misplaced compound words, colloquial names actually help with
better communication. For instance, "Can you take a look at the delete button?" and we

48
simultaneously refer to an identifier for the button, which happens to be called Delete-
Button – and e.g., not btnDelete. Or worse, btnDel.

It becomes as natural to recommend method names as imperative verbs and pronouncea-


ble verb phrases. In that sense, DelUsr doesn't seem very pronounceable, and we'll re-
flect on the name for a bit longer compared to DeleteUser. Even DeleteUserByID
will be relatively easy to understand because every compound word can be pronounced,
and the entire name is pronounced in a natural order.
Verbs can be combined in many ways, and although we don't add pronouns in phrases,
i.e., "we", "me", "you", etc., or "myObject" for that matter, names can still be spoken and
close to human sentences, e.g.:
FHandle: THandle;
procedure HandleNeeded;
function HasHandle: Boolean;
procedure ReleaseHandle;
The above identifiers almost reveal that a Lazy Initialization could be used in the imple-
mentations; a kind of creational pattern in Software Design Patterns that waits to initial-
ize a resource (or process) until the first time the resource is needed.

Component Names on Forms


It is true that most style guides consider prefixes and encoding in names with either the
prefixes or the type as noise, e.g., szName or strName. It also includes compound words
like StringName or NameString and is considered meaningless information by most
style guides, Coding Best Practices or in thoughts behind concepts like Clean Code. We do
not need to specify that an identifier is a variable.
However, the biggest confusion arises from the fact that this type of bad practice is aimed
at variables of primitive types and not complex variables such as TList, TStream and
the like. We have no problem specifying an identifier such as:
SMFStream: TSMFStream; eller
UserList: TList;
Style guides focus primarily on naming field identifiers, methods, properties, classes, and
local variables, and rarely on naming the (in many projects) large number of components
on a form, including the non-visual components. And this is despite the fact that the
names of the components are identifiers and become part of a form's type definition. No
standard style guide or naming convention describes rules for naming components on a
form, if we ignore the early versions of Visual Basic that specifically had prefixes such as
"pnl" for panels, "chk" for checkboxes, "lbl" for labels, etc. They have certainly spurred
many developers to both use the same prefixes and adopt the ideas of Hungarian Nota-
tion, because so many developers have had Visual Basic as a beginner's tool.

49
Nevertheless, our components will probably also have a type definition in their names,
e.g., CancelButton or UserNameEdit. Naming components on forms is quite im-
portant in many ways, as the components can also be subject to test setups. Modern de-
velopment teams are often accompanied by test developers, either as members of the
same team or in separate teams. And although modern IDE tools have functions that
support Unit Tests and the like, many larger projects prefer to separate the responsibility
of testing a system. And most testing tools need to access the inner components of a soft-
ware through debugging facilities to manipulate the functionality of methods and compo-
nents. Names of components will thus also help test developers to get an understanding
of the system, even if they have their own tools, and usually also their own language and
style guide for their test projects, completely isolated from the main project's language
and style guides. But they still want access to descriptive and meaningful names for the
piece of software and data they are responsible for testing.
Technically, names of a form's components are published field identifiers in the form's
type definition since the default access specifier is "published" and until something else is
specified. Technically, they are also resource items, as they are loaded when instantiating
the form's class using CreateForm. But as a field (member variable), the rules in the new
style guide for naming fields should be used, if it wasn't because the rules explicitly only
mention private member variables.
In a side note about fields in records, a rule is mentioned about omitting the F in the
name when a field is a public member variable. Perhaps Embarcadero could extend this
omission to all kinds of public/published fields. In any case, we are left with just a general
rule about descriptive names and Pascal Casing.
Another characteristic of components on form is that the type of a component influences
its name, traditionally. Components such as buttons with imperative sentences for ac-
tions or instructions to do something, e.g., "Cancel" or "Apply", usually will be given an
imperative verb name compounded with the type of the component, e.g., CancelBut-
ton or ApplyButton.

Components such as labels will normally be named as a variable composed of the type of
the component, as will components such as edits, regardless of whether the words are
verbs or nouns, e.g., UsernameLabel and UsernameEdit.

Prefixes in Names
Prefixes in identifiers go back a long way in history. Before we got smarter development
environments, prefixes primarily helped us distinguish between types of variables, as
compilers rarely helped catch mismatches between type and usage, and errors could oc-
cur during execution – typically runtime type errors. Prefixes are a common feature of
many languages, but in Object Pascal prefixes have only been partially intended to pro-
vide a type scope of an identifier, in addition to a few accepted or enforced type prefixes.

50
In many modern languages prefixes are discouraged, and in other languages excessive
use of prefixes (typically to indicate type) is still encouraged, and in some languages a
prefix may even mean something to the compiler's interpretation. Object Pascal has a few
commonly used prefixes for identifiers. Only a few of the prefixes are required, a few are
recommended, and others are optional to prevent scope conflicts and shadowing of iden-
tifiers. Below is a list of prefixes with a brief description and sorted alphabetically.

A for Argument
The "A" prefix is encouraged in parameter names if multiple identifiers have similar
names. For instance, a name of a property can be shadowed by an identical name of a pa-
rameter. An "A" might be inappropriate for a parameter name since the argument is sup-
plied from a calling side and passed through a parameter declaration and definition. But
"P" was already a common prefix for pointers.
procedure TValue.SetValue(AValue: Integer);
begin
if AValue <> FValue then
FValue := AValue;
end;
The "A" prefix will make it clear that an identifier is a scope of the method and will also
not be able to shadow a possible property with the name "Value".

C for Constant
The "C" prefix is encouraged for all types of declarations for constants, except perhaps
string constants. See "S for resource string". Examples:
const
CSpeedOfLight = 299792459;
CDefaultTempo: Word = 120;
E for Exception
The prefix "E" is required for all type declarations of exceptions. Examples:
type
EMathError = class(Exception);
EInvalidOp = class(EMathError);
F for Field
The "F" prefix is required for all private and protected field variables in a class. Examples:
private
FStatus: Byte;
FTempo: Word;
I for Interface
The "I" prefix is required for all type declarations of interfaces. Examples:

51
type
IControl = interface;
IWindow = interface
['{00000115-0000-0000-C000-000000000044}']
function GetControl(Index: Integer): IControl;
end;
L for Local
The prefix "L" is encouraged for local variables in case identical names would conflict with
or shadow identifiers in parameters, variables, fields or names of properties. Example:
procedure TValue.SetPosition(Value: Integer);
var
LPosition: Integer;
begin
LPosition := EnsureRange(Value, 0, 100);
if LPosition <> FPosition then
FPosition := LPosition;
end;
P for Pointer
The "P" prefix is commonly used in type declarations of pointers. Example:
type
PInteger = ^Integer;
S for Resource String
The "S" prefix is recommended in declarations of resource strings and is also encouraged
in declarations of constants of type string. Example:
const
SDatabaseNotConnected = 'Database not connected.';
T for Type
The prefix "T" is required for all other type declarations. Examples:
type
TMIDIMessage = class;
TMIDISysExMessage = $F0;

Naming Best Practice


The precise rules for a naming convention depend on the context in which they are used.
Nevertheless, there are general traits that influence most, if not all, common naming con-
ventions used today.
1) Use short but descriptive names for identifiers, and declarations with scope are
preferred. Avoid declaring global variables altogether.

52
2) Use explicit names, e.g., not "Temp".
3) Use descriptive and meaningful names, e.g., that a variable name must be a pre-
cise explanation of its contents.
4) Do not start names with "Str", "Arr", "Int" and the like. We don't need to tell that it
is a primitive variable.
5) Follow standard naming conventions and write variable names consistently
throughout an entire project.
6) Follow standard stylization for a language and don't use lower/upper case incon-
sistently.
7) Do not reuse names in the same class for different contexts.
8) Do not use the same variable for different purposes in a method, condition, etc.
9) Use natural language to name identifiers.
10) Use a descriptive and meaningful name for a method. A name must specify the ex-
act action of a method.

We can probably find similar lists on the Internet; any list would work if these followed
what we could recognize as Coding Best Practice.

53
Chapter 6
Comments
and Intention
A section on commenting in the new style guide has been simplified compared to the
original style guide. Not surprising when modern concepts have a different view of com-
ments today, with agile mindsets in particular and other concepts like Clean Code. The
agile manifesto, nor Clean Code, does not specifically advocate eliminating comments,
just as the manifesto is probably aimed at excessive documentation, and not documenta-
tion in general. The style guide is also just rules for how we comment when it is necessary
to comment. We will find conflicting recommendations about commenting, whether we
are talking about Coding Best Practice, the thoughts behind Clean Code, or in the rules of
a style guide.
There are various values that can influence our attitudes towards commenting, besides
"working software over comprehensive documentation", there is the recommendation to
use descriptive and meaningful names instead of commenting, and the concept that an
identifier should not be commented to explain its intention, and that we should therefore
perhaps avoid commenting altogether. The main concern with the different points of view
seems to be the fact that comments can become outdated, i.e., that they become obsolete
and that it is not all about maintaining comments increases development costs.
If a company does not have a policy on commenting, then we should probably stick to
Coding Best Practices for when and what to comment, and a style guide for how we com-
ment. The various concepts, approaches, and methods don't really try to eliminate com-
ments entirely, but simply describe what should be written in comments when necessary,
and don't comment just because a style guide or a textbook has described the idea of a
good comment. This relationship makes rules about descriptive and meaningful names
more valuable.
The section in the style guide about commenting is not completely useless, but it should
be seen as rules for how we comment code when commenting is necessary. We can find
lots of resources on good practices, recommendations, and rules, and not to mention in-
teresting books like "Code Complete", by Steve McConnell, and again from "Clean Code".

54
The latter has always been emphasized for comments as being a sign of bad code, but it's
a bit more nuanced than that.
Other non-Object Pascal language style guides may describe rules for commenting in
much more detail than the new Object Pascal Style Guide. In comparison, the Google
C++ Style Guide formulates more rules for when, what and how to comment, and at the
same time recommends descriptive and meaningful names over comments. On the oppo-
site side, we find the Visual Basic Guide from Microsoft, which writes that good practice is
to begin all procedures with a short comment describing the procedure. As with other
topics within coding style, there is no such thing as "one size fits all", and that practices in
other languages can also go against coding best practices.
The new style guide has a bulleted list of guidelines, but they sound like mostly general
rules of good practice in when and where we should comment. The guidelines are not de-
scriptive enough with examples, and if our project or our company has not determined a
policy for commenting, then we should consider looking at Coding Best Practices in when
and what to comment. If only to support the style guide and other methods we use, e.g.,
code review or code-level documentation, and support the recommendations to comment
consistently. Again, arbitrary rules should not be imposed as we can easily question them
and replace them with other arbitrary rules.

Comment Policy
Another misconception is that occurrence of comments is the same as code smell. That is
not entirely true. Excessive use of comments like noisy and obvious comments are seen as
code smell. The first example with SetPosition and comments in the next section
could be a good example of code smell. Intention-revealing comments or code-level docu-
mentation should not be considered code smells. If a policy specifies an obvious comment
for SetPosition, then there is something wrong with the policy.

Few companies have very specific policies for commenting, and in most cases a style
guide stands alone with a few rules. Some teams would consider comments to be noise,
and others might be governed by internal or external guidelines or contracts about when,
how, and what to comment on. It shouldn't come as a surprise, but we will find a signifi-
cant and visible difference in practices or commenting requirements of a hobbyist pro-
grammer with a Tetris app versus codes of engineers controlling a robotic arm on a
multi-billion-dollar rover, who must drive on a distant planet. We can be sure that there
are no subjective discussions and arbitrary use of random personal preferences in the lat-
ter project, where any assessment of methods will have been taken prior to the project.
Nor should we expect or demand the same standard for a small project by a hobbyist pro-
grammer in the entertainment industry as we would for a large and critical project that
might have to go through a type-approval, and maybe also a safety or medical approval of
relevant authorities and in different countries in which the product will operate. The re-
quirements in different fields are so distinct that a dispute over code style rules between

55
two developers from different fields with different requirements and expectations may
seem pointless. Approval processes and certifications require great discipline, as even a
small change to a software can require a new approval in some fields.
Some companies or teams may also require pseudocode as comments that can explain
the intent of the code for reviewers to read. In these cases, a review procedure will most
likely be conditional on a confirmation of comments to avoid inconsistencies between
commenting and code. Such comments are contrary to the common belief that comments
that is a duplicate of code is bad practice. There are many concepts in code review prac-
tices, where some methods eliminate the need for comments and others will require a cer-
tain degree of commenting.
Enforced commenting, e.g., for code-review or code-level documentation, should not per
definition be bad practice, but rather as a necessity and thus shift attention to when and
what we should write and how we write good comments, e.g., to support code-review or a
code-level documentation contract. This means that we can disregard what would gener-
ally be considered a good practice for commenting, but also not dispute the concept of
readable code.

Comment Intention
The different views on commenting code essentially agree on some points. One of them is
the details of the comment should be focused on describing the intention of a piece of
code. Another point is the idea of what not to comment on, i.e., what is considered a bad
comment. Clean Code covers the most common views of what can be considered Coding
Best Practices in commenting code, except that Clean Code does not address commenting
that is enforced from other methodologies or policies.
Concepts that can be thought of as Coding Best Practices are often enthusiastic about the
idea of explaining the code if it is not self-explanatory, without adding unnecessary noise
in the comment. On the other hand, they would emphasize the rule of intention in com-
ments, as with descriptive and meaningful names, if the code cannot reveal its intention.
All comments should describe the intention of a piece of code, and the comment should
not be an obvious or a copy of the code.
The example below visualizes the amount of noise in a comment that describes some-
thing completely obvious. The comment is a copy of the code, it serves no purpose, only
adds noise and more cost in maintaining the code because we may have to formulate a
new comment if we change the code or just the name of an identifier.

56
{ SetPosition stores a new value passed as an argument, if
different, to the field variable FPosition, and then
request to update the control by calling UpdateTrackBar. }
procedure TTrackBar.SetPosition(const Value: Integer);
begin
if Value <> FPosition then
begin
FPosition := Value;
UpdateTrackBar;
end;
end;
If we decided at some point to go for a protected member named Changed instead of
UpdateTrackBar, to make the code more generic and shift the responsibility for trig-
gering the OnChanged event, etc., then we will need to formulate a new comment if we
don't just ignore it. This last situation is also one of the reasons why commenting should
be completely removed, because a discrepancy between comment and code can turn into
a really bad experience for other developers who must maintain the code.
Another word often associated with defining a good comment is "why". No matter how
descriptive a piece of code may be, it rarely expresses why it is constructed as it is written.
Sometimes we're in a situation where we're forced to write code in a not-so-obvious con-
struct, and we'll need to comment to explain why we've constructed the code a certain
way. Most people will probably agree with recommendations about good comments, and
most people will probably also acknowledge that it can be difficult to write comments that
reveal the intent or explain the construction of code. It is not just a simple recommenda-
tion of intention in comments.
On the other hand, it's much easier to write an obvious comment, and maybe it's some-
thing we learned in school that we should just write a comment that will be considered as
a copy of the code, so to speak, and noise by professionals. Many developers struggle with
commenting that can reveal intention because it's hard to find examples of how we write
this type of comment. The following is an attempt to exemplify the purposes of comment-
ing according to the views of Coding Best Practices.
The first example below would fall into the same category as a "why" comment but is also
considered obvious because we should be experienced enough to know that this is a com-
mon code construct, especially for a setter. Professionals always strive for efficient pro-
cesses and low CPU overhead, so an omission of a conditional statement might require a
comment in "why" the condition is omitted, as a contrast to the obvious comment in the
example.
If a conditional statement is omitted in an obvious place, a code review should raise a flag
and ask why the condition was omitted. When to write a "why" comment can be a diffi-
cult task, because the more experienced we become, the more obvious a code construction
is. Thus, inexperienced developers will tend to add a more obvious comment than

57
experienced developers. This is part of becoming a professional developer. A team or pro-
ject can therefore also have a policy around this type of comments, so that the code is not
filled with obvious comments.
procedure TTrackBar.SetPosition(const Value: Integer);
begin
{ Conditional change to avoid CPU overhead. }
if Value <> FPosition then
begin
FPosition := Value;
Changed;
end;
end;
The most common type of code-level comments must be around the code that breaks an
obvious construct, i.e., if we had omitted a conditional statement in the example above.
We can do another example with a call to GetDIBits, an API call to the Windows
Graphics Device Interface (GDI) that retrieves bits from a specified bitmap and copies
them into a buffer. The most obvious call is straightforward:
GetDIBits(FBitmap.Canvas.Handle, FBitmap.Handle, 0, FHeight, @Buffer[0],
BitmapInfo, DIB_RGB_COLORS);

Calls to Microsoft Win32 APIs follow a stdcall calling convention, which means that
arguments are pushed onto the stack from right to left. Bitmap's handle is pushed onto
the stack before Canvas' handle, and that suited the internal behavior of both objects
nicely, as the getters for both handles trigger a series of internal processes. But with
Win64, this little detail in calling conventions has changed.
With the Windows x64 calling convention, the first four arguments are placed in regis-
ters, and additional arguments are pushed onto the stack from right to left. This is not the
root of the problem, but the order in which the compiler evaluates each of the arguments
to be pushed into registers. The order is not defined, which means we can never be sure
which argument will be evaluated first. In our case, handle from an FBitmap.Canvas
would be pushed into a register before handle from the FBitmap, and that changes the
entire internal behavior of both objects. These small details do not make it easy to migrate
from Win32 to Win64.
From an obvious and simple call to GetDIBits, we now need to ensure that the handle
on a bitmap is evaluated before the handle on a canvas. A comment should thus prevent
us from "fixing" the problem with an obvious and direct reference to a bitmap handle, in-
stead of a local variable. We could write a comment describing the change in calling con-
ventions and order of arguments, but the word "evaluation" should guide a developer in
that direction, since GetDIBits is a Windows API call.

58
{ Forces evaluation of Bitmap.Handle before Bitmap.Canvas.Handle. }
LHandle := FBitmap.Handle;
GetDIBits(FBitmap.Canvas.Handle, LHandle, 0, FHeight, @Buffer[0],
BitmapInfo, DIB_RGB_COLORS);

A bad example of a comment for this situation would be "Don't fix!!!" with no explanation
of "why" we are not allowed to change the code. Although that comment might be better
than no comment at all, the lack of a comment that doesn't reveal the intention of the
code can do more harm to the construct, especially when it comes to a developer with a
sincere idea to "optimize the code and clean it up." When to add such comments may be
easier to master than how to write a brief explanation of a construct.

Code-level Documentation
Another example could perhaps be considered a block of noisy information, but it should
be seen as code-level documentation, as it can save a great deal of code-level comments. A
block comment can help describe a common business logic, e.g., data formats in the ex-
ample below. A block comment would then be placed just before the most obvious type-
definition of the class that handles and manipulates these data types. The code-level doc-
umentation should not be confused with comments to the XML documentation, which is
a nice feature described in a later section.
The example is based on a MidiInProc callback function that we use to receive MIDI
messages from the Microsoft Windows Multimedia framework. Callback is a typical pro-
cedure based on a Windows message construction, so we receive dwParam1 and
dwParam2 in the callback. dwParam1 is translated to dwMidiMessage if wMsg is a
MIM_DATA, which is then a MIDI input message from a MIDI device that we have
opened with midiInOpen. The message is wrapped in a LongWord in the following
way:
{ Short MIDI message that are transmitted or received (dwMidiMessage)
are packed into a LongWord value as follows:

LongWord Value Description


-----------------------------------------------------------------
High word High-order byte Not used.
Low-order byte Contains a second byte of MIDI data.
Low word High-order byte Contains the first byte of MIDI data.
Low-order byte Contains the MIDI status.

The most significant nibble of the status byte is the actual status
code ($80-$F0), and the least significant is the MIDI channel ($00-$0F)
if status is not a system message ($F0).
Both MIDI data bytes are optional, depending on the MIDI status byte. }

TMIDIMessage = class(TObject)
class procedure Decode(const Msg: LongWord;
var Status, Data1, Data2: Byte); inline;
end;

59
The level of detail for a code-level documentation depends on the topic and what will be
necessary to understand the topic and can also be simplified in its style. How we style the
details of the block comment could also be subject to rules, but the requirements to use
curly braces, starting at the first word on the same line as the opening parenthesis and
closing parentheses on the same line as the ending text, are consistent with the Object
Pascal Style Guide. Other sets of rules might require block comments to end with a pe-
riod, and perhaps requirements specific to any field, etc.
You've obviously noticed that the two data bytes are named Data1 and Data2, which is a
obvious crime against Coding Best Practices of not naming identifiers with consecutive
numbers as a suffix. However, these names have survived since the 80s, and fortunately
are only used in the callback's internal handling of MIDI messages. Once the status byte
is interpreted, the data bytes are interpreted into more appropriate identifiers. If the sta-
tus byte e.g., is "Note On", data bytes will become a Note number and a Velocity value.
This violation of best practice also shows that it can be difficult to enforce an otherwise
quite simple rule in all circumstances.

Code-level Comments
A third example could be the implementation of a TMIDIMessage.Decode procedure
with some parameters, where we can put the separate data as defined in the block com-
ment above. At first glance, the task seems quite easy; just add the correct bytes from a
message to each of the arguments. We could even leverage type conversion records in the
System.SysUtils unit. An implementation will be obvious, which is why there will be only
few lines of code to unpack and store each byte from a packed LongWord.
Before we continue, this example could also serve as a demonstration of over-engineering
a modest construct that could be solved with a simple bit shifting for a couple of bytes.
The example may demonstrate our knowledge of record-helpers we have found in a li-
brary, but it also demonstrates how it affects the readability of a construct compared to
the following example. If performance and low latency are a requirement, the helpers also
add a little overhead in this construction, but perhaps a good solution if we simply need to
manipulate a single byte in a packed LongWord in another task.
But again, the MIDI specification has another "packing mechanism", or a performance
optimization so to speak, from the early days when the transmission of data was expen-
sive in the first several years of slow serial communication. With a baud rate of just
31,250 (although it was fast at the time), one saved byte here and there could prove to be
of great importance to the experience of the users, in that it could reduce an overall la-
tency (delay). Latency is clearly a major focus area in the world of music.

60
class procedure TMIDIMessage.Decode(const Msg: LongWord;
var Status, Data1, Data2: Byte);
begin
Status := LongRec(Msg).Bytes[0];
Data1 := LongRec(Msg).Bytes[1];
Data2 := LongRec(Msg).Bytes[2];
end;
The MIDI specification was introduced with a running status so that the MIDI devices
did not have to send the same status byte for subsequent data with the same status value
repeatedly. If a MIDI device has only received data bytes, it should have a saved status
byte with the last received status. Although Windows Multimedia has disabled running
status for in MIDI callbacks, this feature can introduce errors if not properly handled by
callbacks, because this opening in the MIDI specification led some MIDI manufacturers
to produce devices that only send NoteOn messages with a Velocity of zero as being
NoteOff messages. Windows Multimedia will signal a callback with a message as is – it
does not convert a NoteOn message.
A simple construction of an obvious implementation in decoding a MIDI message will be
broken because we will implement an early conversion of the aforementioned running
status and every time, we decode a message. We could implement a conversion later in
the handling of MIDI messages, but that would invite inconsistencies at a higher applica-
tion layer. The conversion of status in the example can be solved at the next application
layer and after interpreting MIDI messages, thus introducing less CPU overhead. But the
construct serves its purpose as an example with code-level comments.
class procedure TMIDIMessage.Decode(const Msg: LongWord;
var Status, Data1, Data2: Byte);
begin
Status := Msg;
Data1 := Msg shr 8;
Data2 := Msg shr 16;
{ "Note On" status must convert to "Note Off" if Velocity
equals zero. Otherwise, it could result in hanging notes. }
if (Status and $F0 = CMIDINoteOn) and (Data2 = 0) then
Status := Status and $0F or CMIDINoteOff;
end;
The above comment is written as short as possible, and it does not attempt to copy the
code. It simply tries to explain, briefly and precisely, why additional lines have been
added that extend a decoding, since the MIDI specification allows a running status to
pass unnoticed through a handling of MIDI messages. The comment expects us or a code
reviewer to have a basic knowledge of MIDI messages, and some of that information can
also be written before type definition of a class as code-level documentation. There should
be enough keywords to point developers in the right direction if more careful review of
the topic becomes necessary.

61
Refactoring Comments
A fourth example would be to remove the need for comments by refactoring code from
existing comments. Martin Fowler of "Refactoring" recommends that we should just look
for comments, e.g., that whole blocks of code with comments that tell what the code does,
which can then be replaced by a method that gets a name based on the comment. This
means that the above code and comment can be replaced with a method called "En-
sureNoteOff" or some other name that might reveal some intention.

One argument found on the Internet in favor of commenting code was how complicated a
piece of code could be to reverse the order of characters in a text. E.g., the code would not
reveal its intention completely and how easy it would be to just add a comment saying:
"Reverse the order of the text". The counter argument was to move the code to its own
function and write a revealing name for the function like "ReverseString" that takes a text
and returns a new text. That way we don't need the comment. This is the idea behind
"Refactoring" – we look for such comments.
var
I: Integer;
P: PChar;
begin
SetLength(Result, Length(AText));
P := PChar(Result);
for I := High(AText) downto Low(AText) do
begin
P^ := AText[I];
Inc(P);
end;
end;
The discussion mentioned was with an example in Perl, but the principle is language ag-
nostic. The code to reverse the order of a text in Delphi is shown in the above code snip-
pet from the System.StrUtil unit. Without the name of the function, it can take a few
minutes to interpret the intention of the code. We wouldn't have needed to step through
each line of code if we knew that the construct is part of a function called Re-
verseString that takes a text and returns a new text of type string.

Of course, not all comments and code constructs are suitable for refactoring, and the
problem with a "running status" could be finding just the right name for the function that
ensures all Note Off messages are handled. And that will in most cases be the difficult
part of the task, namely finding the one intention-revealing name, which can also make it
a challenge to move code to logically separate functions.
When we force ourselves to try to find a suitable name for an identifier, we also begin to
look at the task differently. The problem with "hanging" notes is a direct result of a feature
in the MIDI specification that allows devices to use a running status. Although the feature

62
is ignored before MIDI callbacks in Windows and does not convert Note On with 0 in Ve-
locity from MIDI devices that "mistreat" the function, the function may well be in use on
other platforms. The problem can instead be handled by a method that follows the run-
ning status locally, and perhaps noted with a comment in the declaration, for example:
{ Track Running Status and adjust Status if needed. }
procedure SetRunningStatus(var Status: Byte; const Data1, Data2: Byte);

Some developers and teams still use the rule of commenting, at a minimum, public mem-
bers of their classes that describe the intention of a method and any parameters. There is
a long tradition of commenting at the declaration level, and the above challenges could be
solved by such a comment explaining the problem, why, and all the intentions in detail.
This practice, of commenting on declarations, has gradually evolved into documentation
comments using XML elements.

XML Documentation
The new style guide has a new short section on XML comments, a feature that did not ex-
ist when the original style guide was developed. The RAD Studio Help Manual also has a
short section on XML comments and has a few useful links to more resources on the sub-
ject, since the format is compatible with Microsoft XML documentation comments. One
of the advantages of XML comments is that the information can be displayed using the
Help Insight feature in Delphi, but also that the information can be generated or used by
automated documentation processes.
/// <summary>Trigger corresponding expression objects to be re-evaluated</summary>
/// <param name="Sender">Object that should be re-evaluated</param>
/// <param name="PropName">Property that should be re-evaluated</param>
/// <param name="Manager">The bindingManager the expression belongs in.</param>
class procedure Notify(Sender: TObject; PropName: string = ‘’;
Manager: TBindingManager = nil);

The disadvantage of XML documentation is that the information is difficult to read di-
rectly in the source code due to a clutter of XML tags. Above is an example from the new
style guide that visualizes the difficulty of reading the information. Highlighting the infor-
mation with colors will certainly make reading easier, but the Delphi IDE's color options
have no option for XML documentation comments.
Despite the difficulties with the feature, we're sure to see improvements in the future, and
it deserves at least a review in this chapter. According to some suggestions in Coding Best
Practices, the level of detail of such comments should be similar to documentation used to
describe API documentation. E.g., we must describe the intention of a method or
property, and why it is there, and we should describe any business logic that is not
obvious to a developer.
With such a description, it should also include information about any restrictions on ar-
guments passed with a call, e.g., if some arguments must be assigned or must be nil and
how this would affect or lead to errors during a call if invalid references are used. After a

63
description of the method or property, and the arguments, we must describe as a mini-
mum:

• how the return values possibly must be handled,


• if exceptions can be raised and why,
• the similarities with other methods, if any, and
• highlight any unforeseen anomalies and indicate affected relationships.

According to common practice in using XML documentation, all public methods and
properties of a class must, as a minimum, be commented using XML documentation. The
old VCL part of Delphi doesn't make much use of these features, except in some data and
REST components, but the newer FMX part uses the documentation format, though in
most cases just the summary tag and usually only some of the public member of a class.
The level of detail is not quite what is recommended as API documentation; rather, they
are regular code-level comments wrapped in XML format.
In terms of recommending this type of documentation, the new style guide is not explicit.
Any requirements or rules should be formalized by a company, in a project or team. The
problem with the recommendation to write XML documentation like API documentation
is the level of detail for proper API documentation. We can take any random available
documentation and extract a function and review its information. The level of detail of
API documentation can be large and may exceed the capability or intent of the features of
XML documentation. As an example, API details can include tables of data formatting, a
list of possible values in parameters and, not least, a list of return values.
We can start from Microsoft's online documentation, which has many examples of how
APIs are documented, and because developers of Windows applications depend on such
documentation. The same type of documentation can be found for APIs on other plat-
forms, or for instance in integration projects for web services, e.g., RESTful API. This type
of detailed information is essential for developers, and the intention of XML documenta-
tion was really to address that need, including the features to extract these comments for
use in API documentation. With this huge amount of API documentation for even the
simplest function, e.g., as in the detailing of midiOutShortMsg on the next page, would
possibly destroy the readability of defining classes or members in the form of heavy docu-
mentation and XML tags.
Without an integrated editing function of XML documentation in the Delphi IDE, we will
probably never meet the recommendation to write documentation with a correct level of
details. We will likely continue to see code-level documentation and XML documentation
combined in some form of source code documentation. Otherwise, we must assume that
XML documentation is only used as code-level comments if APIs isn’t exactly meant as
published code, e.g., for web services.

64
Most projects or teams will write less docu- API documentation for midiOutShortMsg
mentation for published members of their clas- midiOutShortMsg function (mmeapi.h)
ses in the source code, and far less detail for The midiOutShortMsg function sends a short MIDI message to the
parameters than recommended for APIs. But specified MIDI output device.

the poorer information would instead require Syntax

some form of documentation for additional de- MMRESULT midiOutShortMsg(


HMIDIOUT hmo,
tails, tables, data formats and more, elsewhere. );
DWORD dwMsg

And that way, most developers will feel bur- Parameters


dened by having to maintain multiple sets of hmo
the same documentation.
Handle to the MIDI output device. This parameter can also be the han-
dle of a MIDI stream cast to HMIDIOUT.
Regardless of XML documentation require-
dwMsg
ments, the new style guide provides a few
MIDI message. The message is packed into a DWORD value with the
examples of how we style XML documenta- first byte of the message in the low-order byte. The message is packed
into this parameter as follows.
tion, but the examples also raise questions. An
Word Byte Usage
example appears to have indentation for the High High-order Not used.
summary description, probably not standard Low-order The second byte of MIDI data (when needed).
Low High-order The first byte of MIDI data (when needed).
indentation for a wrapped text enclosed by
Low-order The MIDI status.
XML tags. Indentation or spaces do not affect
The two MIDI data bytes are optional, depending on the MIDI status
visualization in Help Insight, as text is trim- byte. When a series of messages have the same status byte, the status
byte can be omitted from messages after the first one in the series,
med before use, but the text in source code creating a running status. Pack a message for running status as follows:

should be adjusted according to summary tags. Word Byte Usage


High High-order Not used.
Activating Code Formatter in Delphi [Ctrl+D] Low-order Not used.
Low High-order The second byte of MIDI data (when needed).
trims the text and removes the indentation, Low-order The first byte of MIDI data.
which seems to align the wrapped text cor-
rectly unless the wrapped text appears on the Return value

same line as <summary>. However, activating Returns MMSYSERR_NOERROR if successful or an error otherwise. Pos-
sible error values include the following:
code completion using Enter, after writing a Return code Description
line with three slashes (///), will indent sub- MIDIERR_BADOPENMODE The application sent a message with-
out a status byte to a stream handle.
sequent text on the next line with two spaces MIDIERR_NOTREADY The hardware is busy with other data.

after slashes, regardless of the indentation on MMSYSERR_INVALHANDLE The specified device handle is invalid.

the previous line. If we activate the Code For- Remarks


matter, these indentations are removed.
This function is used to send any MIDI message except for system-ex-
clusive or stream messages.
We'll find that text commented with three
This function might not return until the message has been sent to the
slashes is indented with one space after the last output device. You can send short messages while streams are playing
on the same device (although you cannot use a running status in this
slash when we activate the Code Formatter, case).
just like regular comments with two slashes.
All indentations, even spaces, will be trimmed
to just one space. Code Formatter has no settings for XML documentation, which means
that Code Formatter indents all comments after three slashes with a single space.

65
/// <summary>
/// Set of regular <c>TFontStyle</c>. May contains any <c>TFontStyle</c> value
/// but TFont will process only fsOutline and fsStrikeOut values.
/// </summary>

The problem is, although most XML documentation in Delphi would have proper align-
ment of an enclosed text, we might need a mix of indentation that follows the standard
indentation of XML documents. It's just impossible due to inaccuracy in Code Formatter.
Spaces are of course of no importance, but it is about the style guide for a type of code. An
example would be a slightly more sophisticated use of <remarks> tags with nested
<para> tags, for example:
/// <remarks>
/// <para>
/// This is an introductory paragraph.
/// </para>
/// <para>
/// This paragraph contains more details.
/// </para>
/// </remarks>

Whichever formal style guide is used for XML documentation, the Code Formatter will
make it impossible to enforce the style.
The Delphi documentation has a list of supported XML tags, and the Microsoft documen-
tation on XML documentation will certainly offer more information about the intended
use of a specific function. Below are a few more examples to visualize where and how to
use XML documentation in source codes. The examples are not specific but visualize the
amount of text needed to produce a simple description compared to common section
headers.
/// <summary>A class to facilitate communication with a MIDI device.</summary>
TMIDIDevice = class(TObject)
/// <summary>Send MIDI Note On message to the MIDI device.</summary>
/// <param name="AChannel">Which MIDI Channel to play a note (0-15).</param>
/// <param name="ANote">The note to play (0..127). ANote=60 is middle C.</param>
/// <param name="AVelocity">The velocity or attack of the note (0-127).</param>
/// <remarks>A velocity of 0 (zero) would be equal to Note Off.</remarks >
procedure TMIDIDevice.SendNoteOn(const AChannel, ANote, AVelocity: Byte);

The last example below is an example written for Microsoft C#, with adjustments in the
embedded code, and of course replaced with Pascal code. The idea is to compare the same
function in a language. You'll notice that XML tags are missing indentation and for en-
closed text. A formal XML style guide has recommendations for structuring of a XML
document, but the XML documentation in Delphi seems to be styled this way.
You will also notice that the list of available XML tags documented for Delphi is not as
complete as the tags for Microsoft XML documentation and the tags recommended for
C#. For example, we won't be able to use the <example> tag in Delphi from the example
below, or at least it's not listed. The XML documentation feature will be ideal for automat-
ically generating documentation, in extension of published methods in web services, and

66
having it produced as API documentation and made available to developers, although it
might be a bit more cumbersome for a traditional and common code base, that do not of-
fer any kind of services.
Regardless of features and supported tags, the new style guide may need a more detailed
description of styling embedded XML tags, indentation, and enclosed texts. And point out
that the target audience of XML documentation is the users of the code through APIs and
services, and not ideal for developers who need to maintain the source code. If this feature
is to be useful for the latter developers, the XML documentation should be improved with
syntax highlighting in the Delphi IDE and at a minimum for the enclosed texts. The XML
documentation highlighting feature is available in other IDE tools and makes the en-
closed text much more readable.
/// <summary>
/// Adds two integers and returns the result.
/// </summary>
/// <returns>
/// The sum of two integers.
/// </returns>
/// <param name="left">
/// The left operand of the addition.
/// </param>
/// <param name="right">
/// The right operand of the addition.
/// </param>
/// <example>
/// <code>
/// var I: Integer;
/// I := Add(4, 5);
/// if I > 10 then
/// ShowMessage(IntToStr(I));
/// </code>
/// </example>
/// <exception cref="System.SysUtils.EOverflow">
/// Thrown when one parameter is
/// <see cref="Integer.MaxValue">MaxValue</see> and the other is
/// greater than 0.
/// Note that here you can also use
/// <see href=" https://docwiki.embarcadero.com/CodeExamples/Sydney/en/Integer_Type_Helpers_(Delphi)"/>
/// to point a web page instead.
/// </exception>
/// <see cref="ExampleClass"/> for a list of all
/// the tags in these examples.
/// <seealso cref="ExampleClass.Label"/>
function Add(Left, Right: Integer): Integer;

Section Headers
A common type of comment, which is not really a comment, but a heading used to ar-
range constructs into sections, or in other words "groups". We often use a single word, an
identifier, a keyword, and sometimes with two slashes, but most often with curly brackets
that signify the start of a section of related lines of code. Delphi IDE also generates such
headers automatically when we enable class completion during a declaration in a class.
The "comment" is simply the name of the class as a header. That approach ensures that

67
all related implementations of a class can be arranged closely together and is also gener-
ated in an alphabetical order, reflecting the old rule of placing members alphabetically.
The new style guide has written of the rule of ordering members alphabetically, and now
accepts an arrangement by related methods, and makes a comment as a section header
more regular. However, the rule of alphabetical order should not be abandoned com-
pletely, because in case of related methods then they should be arranged alphabetically
inside that group, in accordance with Coding Best Practices and somewhat in same line
with Clean Code, quotes "It is very helpful if names for very similar things sort together
alphabetically and if the differences are very obvious."
The new style guide has no explicit mention of section headers, although activating class
completion creates the comments. A description or intention to arrange related code con-
structs together is missing from the style guide. The intention of such comments would
be consistent with Coding Best Practice and would not be considered noise. The only
mention of grouping logically related code together is for blank lines in the chapter on
"White Space Usage", which also conforms to Best Coding Practice, and Clean Code, link-
ing related constructs together and separating weakly related constructs. Another implicit
mention of the arrangement of related constructions is in the chapter on "Comments" on
single-line comments, where blank line rules apply to comments on related constructions.
Especially in defining multiple classes, not all declarations are revealed by a header. Ra-
ther, they are grouped by the most significant class and related definitions, for example:
[snipped]
property TimeDivision: Word
read GetTimeDivision write SetTimeDivision;
end;

{ TSMFStream }

TSMFEvent = packed record


private
FClock: Cardinal;
[snipped]
end;

TSMFStream = class(TMemoryStream)
strict private
FRunningClock: LongWord;
FRunningStatus: Byte;
[snipped]
end;

{ TSMFTextStream }

TSMFTextStream = class(TStringStream)
private
FDetails: Boolean;
[snipped]

68
This way of arranging constructs into related parts can also be seen in the implementa-
tion section, and is used not only in groupings of implementations, but also in grouping
code into sections that highlight parts of a local construct and make it more readable.
Until now, we have eluded mentioning types of comments other than those enclosed by
the curly brackets. We also have comments in the form of brackets with an asterisk (* *)
and comments with 2 slashes //. In practice, we use all types of comments, but we have
avoided the other types because it must be seen in relation to the strict rules in the style
guide for comments with 2 slashes and in separating the use of the types. The new style
guide does not specify when the different types should be used, although enabling class
completion will use curly braces consistently for grouping.
The strict rules for double-slash comments, also known as single-line comments, are not
about the indentation or space after slashes and before a comment, but about the rules for
blank lines before a single-line comment and another blank line after the comment, if the
comment applies to a group of statements. The last rule is omitted if the comment applies
to a single statement. The rules are not mentioned for the other types of comments.
var
LRect: TRect;
begin
// Left line

Canvas.Brush.Color := clBtnHighlight;
LRect := ARect;
LRect.Right := LRect.Left + 1;
LRect.Bottom := LRect.Bottom - 1;
Canvas.FillRect(LRect);

// Top line

LRect := ARect;
LRect.Bottom := LRect.Top + 1;
LRect.Right := LRect.Right - 1;
Canvas.FillRect(LRect);

// Right line

Canvas.Brush.Color := clBtnShadow;
LRect := ARect;
LRect.Left := LRect.Right - 1;
LRect.Top := LRect.Top + 1;
Canvas.FillRect(LRect);

// Bottom line

LRect := ARect;
LRect.Top := LRect.Bottom - 1;
LRect.Left := LRect.Left + 1;
Canvas.FillRect(LRect);
end;

69
According to the style guide, the example above is a correct way to group related code
constructs with single-line comments. The first comment is the first line of a block of
code, so the comment should not start with a blank line. With the rules for single-line
comments, then the example with the comment on evaluation of handle in the section
about intention of comments, using 2 slashes would also have been correct since the com-
ment is related to forcing evaluation of handle in the line after the comment. But the rules
don't mention lines of related code before the comment, e.g., the added line in the exam-
ple below. The rule in the style guide about single-line comments must always precede a
line and stand alone, and therefore the example below lacks a blank line.
SetLength(Buffer, FBitmap.Height * FBitmap.Width * 4);
// Forces evaluation of Bitmap.Handle before Bitmap.Canvas.Handle.
LHandle := FBitmap.Handle;
GetDIBits(FBitmap.Canvas.Handle, LHandle, 0, FHeight, @Buffer[0],
BitmapInfo, DIB_RGB_COLORS);

We can be confident that this is about a missing description in relation to the omission of
blank lines before and after a comment specified for a line of code, because otherwise re-
lated lines of code will be separated from their construction. If additional blank lines are
applied only to the rules for single-line comments, and the rules have no specific mention
of the other types of comments, then we can circumvent the rules by using curly brackets.
Below is an example, which can be challenged in its stylization, but comments with curly
brackets have the same intention of grouping related codes together without blank lines.
var
LRect: TRect;
begin
Canvas.Brush.Color := clBtnHighlight;
{ Left }
LRect := ARect;
LRect.Right := LRect.Left + 1;
LRect.Bottom := LRect.Bottom - 1;
Canvas.FillRect(LRect);
{ Top }
LRect := ARect;
LRect.Bottom := LRect.Top + 1;
LRect.Right := LRect.Right - 1;
Canvas.FillRect(LRect);

Canvas.Brush.Color := clBtnShadow;
{ Right }
LRect := ARect;
LRect.Left := LRect.Right - 1;
LRect.Top := LRect.Top + 1;
Canvas.FillRect(LRect);
{ Bottom }
LRect := ARect;
LRect.Top := LRect.Bottom - 1;
LRect.Left := LRect.Left + 1;
Canvas.FillRect(LRect);
end;

70
Note that the blank line conforms to the style guide and Coding Best Practices of inserting
blank lines that group related lines of code together, e.g., that the code example distin-
guishes two different colors used. The above example is debatable, but nevertheless it
shows the intention to arrange constructs in related lines of code or in logical parts of
constructs.
Headings in the form of a comment are quite normal, and often with a single enclosed
word. The style guide does not describe these types of comments, and it would be good
practice to agree on which of the comment types should be used when and how. And
maybe look at the comment’s suggestions in Delphi's documentation. It is not necessary
to add section comments everywhere, and as with Coding Best Practices, code constructs
and the names of identifiers should be descriptive and meaningful enough to minimize
commenting.
After placing comments as in the above example, we should also remember to analyze the
code and see if it can be refactored differently, and remove the need for comments, as in
the thoughts behind Refactoring. This should mean that we should look at the example
from a different angle, and perhaps think a bit traditionally with local functions that re-
turn each side of a rectangle. Another approach could just be a record helper for TRect,
either by introducing properties for each side of a rectangle or adding functions that re-
turn a side of a rectangle, and perhaps with a default width.
begin
Canvas.Brush.Color := clBtnHighlight;
Canvas.FillRect(ARect.GetLeftEdge);
Canvas.FillRect(ARect.GetTopEdge);
Canvas.Brush.Color := clBtnShadow;
Canvas.FillRect(ARect.GetRightEdge);
Canvas.FillRect(ARect.GetBottomEdge);
end;

A record helper for a rectangle would be a good approach, especially if the helper's meth-
ods can be reused in other tasks. The example is a simple code construction, such as it
does not account for overlapping pixels in the corners, but the example serves a purpose
by illustrating the philosophy of examining comments with a different point of view. In
that sense, the thoughts behind Refactoring are completely on track, but at the same time
be aware that not all comments are suitable for refactoring.
type
TRectHelper = record Helper for TRect
function GetBottomEdge(const AWidth: Integer = 1): TRect;
function GetLeftEdge(const AWidth: Integer = 1): TRect;
function GetRightEdge(const AWidth: Integer = 1): TRect;
function GetTopEdge(const AWidth: Integer = 1): TRect;
end;

The definition of a record helper could be as in the above example and would also remove
a hardcoded width, which should also be seen as bad practice.

71
Debugging Comments
It's no accident that so far, we've used curly braces for regular comments, and it's part of
the process of creating consistency in when we should use curly braces, 2 slashes, or pa-
rentheses with stars. The style guide has no rules about when different types of com-
ments should be used as part of the code, and we often just see what might appear to be a
random use of comment types, or a consistent use of only one type, e.g., two slashes.
However, the Delphi documentation provides recommendations for when we should use
the different comment types, which provides a starting point for what this manual should
recommend. The recommendations are added in the last section of this chapter and can
be found in the Delphi documentation under a chapter called "Fundamental Syntactic El-
ements."
The recommendations in the Delphi documentation should perhaps have had a brief
mention in the style guide, as it might make it possible to create a consistent use of com-
ment types, e.g., by making curly brackets part of grouping code constructs, section com-
ments, code-level comments, and code-level documentation. These comment types are
mostly static and can be considered part of code constructs.
We often see code commented out using 2 slashes, surely because this is also made easy
by selecting a block of code and using the hotkeys [Ctrl+/] or [Ctrl+']. It will add two
slashes to each line or remove slashes from each line if they already exist. This mecha-
nism is often used to debug parts of code construction, simply by hiding code temporarily
from the compiler and marking them as comments, for example:
SetLength(Buffer, FBitmap.Height * FBitmap.Width * 4);
// { Forces evaluation of Bitmap.Handle before Bitmap.Canvas.Handle. }
// LHandle := FBitmap.Handle;
// GetDIBits(FBitmap.Canvas.Handle, LHandle, 0, FHeight, @Buffer[0],
// BitmapInfo, DIB_RGB_COLORS);
GetDIBits(FBitmap.Canvas.Handle, FBitmap.Handle, 0, FHeight,
@Buffer[0], BitmapInfo, DIB_RGB_COLORS);

With the above example, it would be possible to examine the process for both code con-
structs by switching between 2 slashes and see what happens with different orders of
evaluation. It is important to emphasize that according to Coding Best Practices, we do
not store these types of comments, let alone request code review without further infor-
mation. These comments are purely for debugging, hence debugging comments, and
should be removed before commit.
The third comment type with parenthesis and asterisk can be used in the same respect,
by commenting out large parts of a code, e.g., an entire definition of a class and its imple-
mentation, to hide it completely from the rest of the codebase. Comment types can be
nested and mixed in almost any combination, except with overlapping tags. It is, for in-
stance, not possible to use (* { Comment *) }.

72
The above code example could be fully commented out by enclosing the entire code con-
struct with parentheses and stars if and only if parentheses and asterisks do not appear
elsewhere in the construct. Curly brackets and all slashes will be enclosed and ignored,
e.g.:
(*
SetLength(Buffer, FBitmap.Height * FBitmap.Width * 4);
// { Forces evaluation of Bitmap.Handle before Bitmap.Canvas.Handle. }
// LHandle := FBitmap.Handle;
// GetDIBits(FBitmap.Canvas.Handle, LHandle, 0, FHeight, @Buffer[0],
// BitmapInfo, DIB_RGB_COLORS);
GetDIBits(FBitmap.Canvas.Handle, FBitmap.Handle, 0, FHeight,
@Buffer[0], BitmapInfo, DIB_RGB_COLORS);
*)

Another common use of debugging comments as code-level documentation is end-of-line


comments. Although these types of comments invite short and precise descriptions, all
comment types can be used as end-of-line comments, but two slashes are most used, for
example:
SetLength(Buffer, FBitmap.Height * FBitmap.Width * 4);
LHandle := FBitmap.Handle; // Note: Triggers Changing event.
GetDIBits(FBitmap.Canvas.Handle, LHandle, 0, FHeight, @Buffer[0],
BitmapInfo, DIB_RGB_COLORS);

In the same example, earlier comment surrounded by curly brackets is removed. A devel-
oper may have had no idea about the concerns of compilers for Win64 and the order of
evaluation, as in calling conventions, but somehow concluded that the problem was asso-
ciated with the call when referencing handles. In the absence of a better description or un-
derstanding of the problem, the comment will at least help the next developer not get
confused by a debugger jumping around in an OnChange event somewhere. The com-
ment can attract the attention of a developer approaching the code in debugging mode or
reading the code to find a different problem.
The purpose of debugging comments is not to write "Fixed!" and add a bug ID for the
commit and indicate that we fixed a reported bug. It will be considered noise. The pur-
pose is to add additional information in case developers need to debug the same piece of
code where a previous developer noticed strange behavior and we don't need to reintro-
duce a previous bug in an attempt to resolve another unrelated issue. Although the style
guide does not provide any rules about how we use comments, it would be good practice
to agree on consistent use of available comment types. At least at the team or project level.

Comments and Coding Best Practices


Considering all the topics in this chapter, there are also thoughts that the presence of
comments is a sign of bad code, code smell. However, these are not thoughts coming
from Coding Best Practices, but rather from a misunderstanding. This is not an attempt
to write our own Coding Best Practice for commenting, but rather an overview of various
and available resources on the topic of programming and commenting. And an attempt to

73
summarize a list of the most common recommendations about commenting. The list
should respect various requirements in policies on commenting, for contracts and from
practice in peer and code reviews and in automatic generation of documentation.

• Make the code obvious and self-explanatory.


• Do not copy the code as comments.
• Comment intention or clarifications.
• Consider refactoring code and removing the need for a comment.
• Good comments are not an excuse for bad code.
• Make alerts or notes about abnormal behavior.
• Be consistent in the use of comment types.
• Problems explaining code are possibly rooted in problematic code.
• Do not comment the end of a block of code.
• Do not comment out code. Remove it before commit.

There are lots of resources about don'ts on the Internet, e.g., "don't be an idiot when you
write a comment", but above all, avoid being inconsistent in commenting, either in styli-
zation or in the purpose of writing objective comments that can devalue the idea of using
comments in code constructs. If the source code is smeared with noisy and obsolete com-
ments, we start to ignore even the good comments.
Finally, we have a list of suggestions from the Delphi documentation about how and
when to use the three types of comment characters. Perhaps these suggestions should
have been part of the new style guide:

• Use 2 forward slashes "//" to comment out temporary changes made during de-
velopment. We can conveniently use the editor's CTRL+/ (slash) mechanism to
quickly insert 2 slashes as we work.
• Use parentheses and stars "(* *)" both for development comments and to uncom-
ment a block of code that contains other comments. This comment type allows
many lines of code, including other comment types, to be removed from the com-
pilation.
• Brug krøllede parenteser "{ }" til dokumentation om, hvad vores intention var
med udviklingen af koden – og evt. som section headers.

74
Chapter 7
Statements
The new style guide has plenty of examples of how to style different types of statements,
and this chapter will not be a repeat of what the style guide has already described. All
sections will be reviewed for what may be missing, e.g., with statement is not described,
and we will thus describe any statements that are not found in the new style guide. We
will also highlight slightly atypical constructions of statements that have already been
described.
And especially with new features in the language, the use of the features depends on
backward compatibility requirements of older compilers, e.g. shared libraries or
components, or source code intended for customers, will delay adaptation to such new
language features. Most newly introduced language features are improvements to the
language and worth studying. And as with new language features, the question of
stylization comes naturally.
Image by xkcd.com, and licensed under a Creative Commons Attribu-
tion-NonCommercial 2.5 License.

75
Inline Statements
Some might think that topics like local variables would be sufficiently covered by the ex-
amples in the new style guide, or the ideas of inline variables and constant declarations
are so simple they are almost self-explanatory. But with new features like inline variables
and declarations of constants, there is a lack of support in styling for new language fea-
tures in Code Formatter. Code Formatter has not been improved in Delphi 11.
Inline variables and declarations of constants are styled by Code Formatter as if they were
declared as traditional local variables or constants. It can be frustrating if the Code For-
matter is activated often. The lack of support thus increases the work of ensuring correct
code style, not to mention carefully double-checking the changes between our local code
and the current revision on a branch or trunk before we commit, just to make sure the
Code Formatter hasn't accidentally broken stylization of the code. According to the new
style guide, declarations of inline variables must be styled as:
var I: Integer;

But the Code Formatter will format the above code as:
var
I: Integer;
Clearly, the was keyword triggers the Code Formatter to style an inline variable as a local
variable. All inline variables initialized with a value or multiple declarations of variables
on the same line will be formatted as if they were local variables, for example:
var I: Integer := 1;
var A, B: Double;
will be formatted to:
var
I: Integer := 1;
var
A, B: Double;
It is not possible to declare inline variables with a common keyword var as in declarations
of local variables. When the declaration is terminated with a semicolon, then we need to
add the keyword for additional declarations of inline variables. Multiple variables on the
same line in a declaration, e.g. A and B, are also considered bad practice by the new style
guide as well as the original style guide, but any attempts to separate each local variable
on a separate line, e.g.:
var
A,
B: Double;
will be formatted to:

76
var
A, B: Double;
This also applies to inline variables, but declarations of inline variables separated by lines
look terrible enough with this stunt, so it doesn't make much sense to separate them any-
way. We'll need to add the variable type for each locally declared variable to suppress
Code Formatter's stylization of multiple variables on one line, but we can't suppress the
stylization tool for inline variables as they were local variables. The problem is the same
for local declarations of constants and inline constants, except of course that it is not pos-
sible to declare multiple constants in a single statement as with declaration of variables.
That's not the only problem with Code Formatter, as it has other bugs with blocks of
statements. Once we become familiar with inline constants and variables, we will also
discover that, unlike local, global, or field variables, each declaration of an inline variable
is a line of code when the variable is initialized with a value. We can trace through an in-
line statement, add breakpoints to inline statements, and inspect their values at initializa-
tion time using the debugger.
If an inline variable is not initialized with a value, the debugger will skip the inline decla-
ration as if it were optimized out, but the variable is somewhere on the stack, and most
importantly, the declaration counts as a statement or line of code, as if it were an "if
True then ;", or an empty begin/end pair after a conditional statement.

The problem is not the debugger, or the compiler for that matter, but the fact that an in-
line statement is now thought as a line of code, introducing a challenge to the Code For-
matter. With inline declarations, it is possible to construct code such as:
if A > 0 then
var I: Integer := 0;
A := B;
The last line is not part of the inner block of code that is executed if the condition is met,
unless we add a pair of begin/end. And the problem is introduced by the fact that the
Code Formatter will format the above code to:
if A > 0 then
var
I: Integer = 0;
A := B;
The last line is now indented after the var keyword as if the line was part of the inner
block of code. However, it is not, just as the declaration of the inline variable is split. Code
Formatter has no problem if the keywords, begin/end, are used with the code block,
except for the splitting of the inline statement.

77
The above example will still probably state a logical error, but stylization of the construc-
tion will not help the readability of the code and will certainly introduce uncertainty with
the intention and in the control of the flow in the code.

if then else Statement


The examples in the new style guide are basically identical to the examples from the origi-
nal style guide. An important detail has been added in the new style guide at the end of
the section, namely whether we should use "if Assigned(Ptr) then" or "if Ptr
<> nil then". However, it says that teams at Embarcadero are more inclined to check
for nil, without mentioning the reason for this. The most likely reason must be a slightly
different behavior with ordinary variables compared to procedural types, and therefore
control statements with nil can be more explicit than with Assigned.

Nevertheless, stylization of if-then-else statements is supported by Code Formatter and


will reformat any incorrect stylizations of code constructs. A minor detail must be the rec-
ommendation not to use unnecessary parentheses around Boolean expressions, e.g. (A <
B). However, they are not removed by Code Formater, as there would be a risk of chang-
ing the entire logic of a statement, e.g., in the order of evaluations. Spaces will be adjusted,
e.g., ( A<B ) will be formatted as (A < B).

The simplest part of if-then-else statements is probably the indentation of code blocks
that separate outer and inner code blocks into visually separate constructs. The most
complex part of an if-the-else statement must be the large number of Boolean expressions
we can put into a single conditional statement, which makes stylization and readability of
these expressions even more important. One thing is a simple A < B expression, another
thing is many expressions that goes beyond the right margin, and when and how these
are broken into continuation lines.
But when Code Formatter is pushed in its ability to decode multiple expressions, it also
starts to show signs of errors, e.g., in line breaks, continuation lines are indented by just
one space and remove other spaces or ignore missing spaces. Fortunately, removing a
space between a Boolean operator like not and an opening parenthesis, e.g., not (A >
B), just a matter of changing a default setting for spacing around unary prefix operators
to "preserve spacing", because otherwise it will involve work to ensure that correct usage
of spaces is observed. We must write stylization of not operators manually, as Code For-
matter will ignore a missing space.
A space between a Boolean operator and parentheses is the common practice, although
not explicitly mentioned in the style guide. We can count approx. 140 occurrences of
"not (" versus one occurrence of "not(" in a unit such as Vcl.Controls.pas, and the
same picture holds for the Delphi libraries, supports the common practice.

78
We know that a few developers will raise a few arguments, especially that the not opera-
tor is a unary operator. But since the operator is a word, it has some limitations compared
to "normal" unary operators like @ or ^, that we need parentheses to make the operator
unary. And even more so because the operator is considered part of the Boolean operators
rather than unary operators. We can imagine the following:
Enabled := not (A > B);

It is possible to remove the space between the not operator and parentheses, and Code
Formatter with the default setting will remove the space and format the line to:
Enabled := not(A > B);

The problem arises if we consider the following lines of code with variables:
Enabled := A > B;
Visible := not Enabled;
We are unable to remove the space after not in the last line, and Code Formatter will not
change the styling of the line unless we add additional parentheses.
The not operator is also not a function that takes operands as arguments in parentheses.
the not operator is primarily a Boolean operator, along the lines of and, or, and xor, that
take Boolean operands, with or without parentheses, and apply standard rules of Boolean
logic. Applying different spacing rules depending on a Boolean operator should be consid-
ered inconsistent and bad practice, so common practice with Boolean operators should be
considered proper stylization.
Besides the space between Boolean operators, multiple Boolean operations can reduce the
readability of conditional statements to a near impossibility, if stylization becomes arbi-
trary and inconsistent. A mental mapping and decoding of conditional statements in the
evaluation of multiple Boolean operations at multiple levels is one of the most time-con-
suming tasks for a developer who must maintain a piece of source code. A conditional
statement determines the flow of a program, and all developers should have full control
over that flow, including all possible values of variables accessed in the evaluations.
One of the simplest recommendations for reducing the complexity of a conditional state-
ment is the same philosophy behind the approach to comments. If a conditional state-
ment becomes too unmanageable, e.g., in the evaluation of multiple operations and oper-
ands, we should consider refactoring that statement, and especially with a design of code
that can be reused. We can imagine the following conditional statement, which is like the
one we can find in the SetBounds method of TControls:

if (ALeft <> FLeft) or (ATop <> FTop) or


(AWidth <> FWidth) or (AHeight <> FHeight) then

79
Note that the line is broken after an or operator, which will also apply to and or xor op-
erators. All conditional statements will be broken into lines between operations following
a Boolean operator, unless a single operation spans an entire line and must be separated
by a space. The not operator follows the same line as or the first line of the operation it is
to negate, that is, it never ends a line.
The above example is not that unmanageable, but we can find lots of real-life conditional
statements that are far more complex in size and operation than this one, but it has some
Boolean operations and lines, and not much is needed to change it and achieve a little bit
of confusion forcing a developer to evaluate each and every logical operation to confirm
the intention of this conditional statement:
if (ALeft <> FLeft) or (ATop <> FTop) and
not ((AWidth = FWidth) and (AHeight = FHeight)) then
Note that the not operator follows its operand(s). With the above example, a developer
will stop if he must confirm that both examples result in the same process for all situa-
tions. It's not that big of a difference between the two examples, but risks with conditional
statements that are so complex that it should lead to the idea of refactoring the code into a
more readable statement. Especially if same conditional statements are used in several
places, then we should consider adding a function with a meaningful name, for example:
function BoundsEqual(ALeft, ATop, AWidth,
AHeight: Integer): Boolean;
begin
Result := (ALeft = FLeft) and (ATop = FTop) and
(AWidth = FWidth) and (AHeight = FHeight);
end;
This method will not only make the example above less complex, but it will also make the
code somewhat more readable, for example:
if not BoundsEqual(ALeft, ATop, AWidth, AHeight) then

A final interesting aspect of if-then-else statements is the order of the evaluated operands.
Most developers don't think much about the order in which they use identifiers within a
simple operation in a conditional statement; most write it unconsciously, in the same way
they would pronounce a statement, for example:
procedure SetPosition(AValue: Integer);
begin
if AValue <> FValue then
FValue := AValue;
end;
Most developers intuitively write conditional statements and variables in an order like in
the examples above, without thinking that this also increases readability. We always want

80
to evaluate a new value (AValue) first in relation to the old value (FValue), and not so
much to evaluate the old value in relation to the new value. In short, the order in which
the variables are evaluated is not random and is an equally important part of controlling
the flow, regardless of whether we are working with or without full evaluation of oper-
ands.
This is also the behavior we use when we create resources in one particular order and re-
move them again in a reverse order, for example:
FSource := TList.Create;
FTarget := TList.Create;
FTarget.Free;
FSource.Free;
This behavior makes it easy to comment out innermost blocks of code or smaller frag-
ments of code, e.g., when we need to debug and find errors:
FSource := TList.Create;
// FTarget := TList.Create;
// FTarget.Free;
FSource.Free;
This also makes it easy to modify the code for changing needs, for example:
FSource := TList.Create;
if A > B then
begin
FTarget := TList.Create;
FTarget.Free;
end;
FSource.Free;
This kind of Last-In-First-Out approach is also useful in code constructs, and how varia-
bles are ordered in conditional statements not only affects the order in the evaluation of
variables, but also how it increases overall readability.

for, while, repeat Statement


Unlike the original style guide, which had a section for each of these statements, the new
style guide has collected these statements into one section. Perhaps because the examples
are few, simple and they all follow similar rules. for and while statements have the
same indentation problems with Code Formatter as inline variables, as described with if
statements, and in fact we can easily reproduce the problem with the formatting, for ex-
ample:

81
for var I: Integer := 0 to 10 do
var J: Integer := 0;

while A > B do
var I: Integer := 1;

repeat
var I: Integer := 1;
A := A + B;
until A > B;
The above construction is technically possible and has the correct stylization, and how-
ever flawed or illogical it may be, the problem is that Code Formatter will stylize the entire
construct to:
for var I: Integer := 0 to 10 do
var
J: Integer := 0;

while A > B do var I: Integer := 1;

repeat var I: Integer := 1;


A := A + B;
until A > B;
The above indentation does not follow the recommended stylization or the logical flow of
the process. Relying on the automatic formatting tools can thus be a bit risky, emphasiz-
ing stylizing code constructions as we write, completely removing the need for, e.g., Code
Formatter.
A risk would be that we trust the result of Code Formatter as being a correct stylization. If
we, for instance, were unsure how to style an inline variable, we could activate the tool
and accept the output of the formatted code as correct. A correct and incorrect stylization
of inline variables is:
for var I: Integer := 0 to 10 do
begin
// Correct
var A: Integer := 1;
// Incorrect
var
B: Integer := 2;
A := A + B;
end;
As with conditional statements, loops, especially while and repeat, can be constructed
with complex conditions, but they rarely exceed a recommended one-line size. If a loop

82
needs to break lines, we should consider refactoring the construct with the same philoso-
phy of avoiding commenting. A slightly unusual while loop, but still valid, found in one
of Delphi's libraries could be:
Resource := ResList;
while (Resource <> nil) and
((Resource^.Owner <> Owner) or (Resource^.HashCode <> ResHash) or
not CompareMem(@Resource^.Data, @ResData, ResDataSize)) do
Resource := Resource^.Next;

The construct can be difficult to read, and most developers would need a few minutes to
understand the intent. These types of constructs that do not meet the recommendation to
use single line in while loops should get the attention of developers and consider refac-
toring the construct in a different way with a function and of course combine it with
meaningful names, e.g. .:
function ResourceNotEqual(AResource: PResource; AOwner: TThreadID;
const AData; ADataSize, AHash: Word): Boolean;
begin
Result := (AResource <> nil) and
((AResource^.Owner <> AOwner) or (AResource^.HashCode <> AHash) or
not CompareMem(@AResource^.Data, @AData, ADataSize));
end;

[snip]

while ResourceNotEqual(Resource, Owner, ResData, ResDataSize, ResHash) do


Resource := Resource^.Next;

The function itself is greatly simplified, and we can even make the function a published
method in a class and use the inline directive if performance is a factor.
Perhaps the name of the function, ResourceNotEqual, could have been more mean-
ingful as a ResourceEqual function, but at least the refactored while loop has been
moved as is, and given a name that reveals an intention that was not present in the origi-
nal loop . The logic in the code has been moved as it was constructed, because the idea be-
hind Refactoring is that we preserve the logic and reduce the requirements for setting up
new tests. Any refactoring of the logic must be based on a balance of readability and risks
of changing the conditions in the loop, which can however be supported by valid tests.
A final problem is with continuation lines and Code Formatter, where all continuation
lines are indented with only one space. Without continuation lines the indentation is cor-
rect, but the above first example would be stylized as:
while (Resource <> nil) and
((Resource^.Owner <> Owner) or (Resource^.HashCode <> ResHash) or
not CompareMem(@Resource^.Data, @ResData, ResDataSize)) do
Resource := Resource^.Next;

83
The difference is almost unnoticeable, but a versioning system would start by highlight-
ing the changes and asking for an "description" of the changes, even if they are just spaces
with no impact on the logic or flow of the process.

case Statements
The original style guide had an example that accepted blank lines between each condition
in a case statement, and even a blank line between the case line and the first condition,
and between the last condition and the end of the case statement. This stylization is
rarely seen and not practiced very often in the real world. The example is not completely
omitted in the new style guide but is simply without spaces between the conditions.
case x of
csStart:
begin
j := UpdateValue;
end;
csBegin: x := j;
csTimeOut:
begin
j := x;
x := UpdateValue;
end;
end;
Vi har bemærket, at stilguiden accepterer forskellige typer af betingede linjer, f.eks. en en-
kelt kodelinje på samme linje som betingelsen, eller en kodeblok lige under betingelsen.
Desværre vil Code Formatter med defaultindstillinger bryde alle kodekonstruktioner op i
nye linjer. Her vil vi være nødt til at ændre en indstilling under "Line Breaks" ved "Line
breaks before single instructions in control statements" til "No". Det vil flytte statements
på en enkel linje, flytte omsluttet kode i begin/end til nye linjer, og kun single-line-
statement vil blive flyttet på samme linje som betingelsen.
However, control statements are also used in other statements, e.g., while, and it will
also affect the styling of these single-line statements. They will simply be moved to the
same line as while if they are not enclosed by begin/end. The only solution is either
"Yes" in the option and accepting single-line statements broken into new lines just below
the condition, or an option like "As is" and then manually writing control statements styl-
ized as recommended.
case statements are the only type of construct that would require at least three levels of
indentation unless we put all single-line statements on the same line as the conditions.
And levels of indentation are used to give us the best possible overview of the construct
and the flow of execution. As with previous sections, case statements can also be stylized
far off the recommended stylization of case statements.

84
As with code constructions and combinations of statements and inline variables men-
tioned earlier, the output of the Code Formatter can make case statements look terrible.
By typing "case" followed by an identifier of a certain type and enabling code completion,
the editor will often construct a case statement with all conditions for a type of enumera-
tion, e.g., will list all enumerators as conditions. A simple example with recommended
stylization of case statements could be:
case VertScrollBar.Style of
ssRegular: ;
ssFlat: ;
ssHotTrack: ;
end;
If we enable Code Formatter with default settings, it will stylize the above example by
breaking it up into new lines after each semicolon. Below are added a few statements and
perhaps an inline variable, for example:
case VertScrollBar.Style of
ssRegular:
var I: Integer := 1;
ssFlat:
A := B;
ssHotTrack:
B := A;
end;
And activating Code Formatter will result in:
case VertScrollBar.Style of
SsRegular:
var
I: Integer := 1;
SsFlat: A := B;
SsHotTrack: A := B;
end;
Another problem arises in that the Code Formatter will capitalize the first letter of each
identifier, even though the identifiers are references to declared names of enumerators
that are required to use lowercase prefixes. They happen to be part of the only exception
to the rule that all identifiers should follow the rules of Pascal Casing. The above refor-
matting just adds more work to ensure stylization according to the recommendations and
makes the use of Code Formatter extremely unreliable.

Handling of Exceptions
Constructing code with exception handling is perhaps one of the most misunderstood
features of all modern programming languages. Not so much in terms of stylization, but

85
rather in terms of correct constructions of the features of the language. The functions of-
ten lead to bad practices in handling exceptions, and many times to misuse, simply be-
cause we have little or no understanding of what really happens to the flow during execu-
tion. It is often revealed by looking at how the handling of exceptions is constructed.
The original style guide has only one example with no description, which has now been
extended with an additional example and a brief description. Unfortunately, the high-
lighted example of a try/except block nested in a try/finally gives the impression
that nesting multiple try/finally and/or try/except blocks is a proper approach.
And because developers can have a hard time understanding what's going on, disagree-
ments arise when it comes to protecting multiple resources in the event of exceptions. In
most cases, we simply see a nested try/finally block for each resource we want to
protect as being the safest, and this is also evident in styling, e.g.:
Source := TList.Create;
try
Target := TList.Create;
try
// Manipulate Source and Target
finally
Target.Free;
end;
finally
Source.Free;
end;
The above example shows a level of uncertainty for a developer, and if we had three or
more resources that we want to protect, then we would simply nest as many try/fi-
nally blocks as we thought necessary. The recommended practice and stylization in
handling exceptions is much simpler:
Target := nil;
Source := TList.Create;
try
Target := TList.Create;
// Manipulate Source and Target
finally
Target.Free;
Source.Free;
end;
or

86
Source := nil;
Target := nil;
try
Source := TList.Create;
Target := TList.Create;
// Manipulate Source and Target
finally
Target.Free;
Source.Free;
end;
Initializing both Source and Target with nil before a try/finally block, and in-
stantiating both resources in an inner block, is probably also the simplest approach, espe-
cially if we have multiple resources we want to protect. The construct must ensure that
both Source and Target are actually valid references or just nil, and never contain
garbage (random addresses). The description of the method TObject.Free would ex-
plain why this is possible and why a call to Free on nil will not result in an error.

The execution of the method Free was designed with the intention of checking itself for
nil, as opposed to a direct call to a destructor of an object, Destroy, which will of
course give an access violation if it is a nil. This behavior will never change, as it would
completely break the entire object structure of Delphi and all systems built around these
methods. A call to the Target.Free method thus corresponds to:

if Target <> nil then


Target.Destroy;
Another popular approach is a call to the FreeAndNil procedure in the SysUtils library.
The above example signals the initialization of variables, regardless of whether they are
local or field variables, and will make no difference to FreeAndNil. If Source and
Target are field variables used with references across an object, then FreeAndNil will
make sense. FreeAndNil corresponds to:

Target.Free;
Target := nil;
We just ignore that the reference to Target will technically be moved into a local varia-
ble and Target replaced with a nil before Free is called on a temporary local variable.
This ensures that any references to the Target are not used during the destruction of the
object if the references are validated consistently. FreeAndNil also means that a varia-
ble is checked against a nil again, which implies an unnecessary CPU overhead for:

if Assigned(Target) then
FreeAndNil(Target);

87
The above will actually translate to:
if Target <> nil then
begin
if Target <> nil then
Target.Destroy;
Target := nil;
end;
Exception blocks add only a small but still noticeable overhead to the CPU. Throwing ex-
ceptions just adds a lot of overhead. It is bad practice to rely solely on catching exceptions
instead of using our programming skills. An important attitude behind Coding Best Prac-
tices is to avoid exception blocks if we can actually control the flow of the execution using
common code constructs. The worst example I've come across in real life has to be a func-
tion that was supposed to return an integer from a string. And because there were often
values that could not only be an empty string, but also consist of one or more spaces, be-
cause users often use space bar to "delete" content, the function was implemented as what
we would consider bad practice :
try
Result := StrToInt(S);
except
Result := 0;
end;
The above exception handler was constantly triggered, and it had a very noticeable im-
pact on the speed when listing data in a grid, but no one questioned either the perfor-
mance or the construction. A better implementation would simply have been:
Result := StrToIntDef(S, 0);

Another good implementation with conditional statements, trimming, and so forth, will
not only conform to Coding Best Practices, but could also prevent a bad implementation
from using, e.g., 10,000 times more CPU by throwing exceptions rather than an imple-
mentation without the need for exception handling. As the documentation for Delphi
points out, requirements for exception handling affect the size of code and penalty in per-
formance, and as in Coding Best Practice, these language features are better suited for
very specific conditions.
Exception blocks should only be used if we are unable to control the flow of execution
ourselves, meaning we transfer control of execution to areas beyond of our control. We
should be able to handle common conditions without needing to raise an exception, and
we shouldn't even consider exception blocks when we have full control over the execu-
tion. When reading from and writing to files, communicating over a network, calling
third-party libraries, and handing over control of execution, we should consider exception
blocks if we have no way to handle errors properly, or exceptions are a risk, e.g.:

88
if FileExists(AFileName) then
begin
Target := nil;
Source := TStringStream.Create;
try
try
Source.LoadFromFile(AFileName);
Target := TMemoryStream.Create;
// Manipulate Source and Target
except
// Handle exception
raise;
end;
finally
Source.Free;
Target.Free;
end;
end;
The above example visualizes the problem of loading from a file system, e.g., that we are
handing over control to an external file system, the file may be corrupt, the connection to
a drive may be disconnected, etc., and we need to be able to continue after an exception,
perhaps giving the user the option to try reloading the file or selecting a different file.
The point must be that we don't need to raise an exception just because the file doesn't ex-
ist. We should be able to check and handle that. An exception should be, well, something
exceptional.
The styling of exceptions blocks, especially try/finally, is simple, but the style guide
might miss a few examples of how we style exceptions with one or more handles, as it
might be tempting to save a few lines, for example:
try
Result := A / B;
except on E: Exception do ErrorDialog(E.Message, E.HelpContext);
end;
or
try
Result := A / B;
except on
E: Exception do ErrorDialog(E.Message, E.HelpContext);
end;
And real styling will require multiple lines when there are multiple handlers, e.g.:

89
try
Result := A / B;
except
on E: EZeroDivide do
ErrorDialog(E.Message, E.HelpContext);
on E: EOverflow do
ErrorDialog(E.Message, E.HelpContext);
on E: EMathError do
ErrorDialog(E.Message, E.HelpContext);
else
raise;
end;
How each exception works, why exceptions occur, and how to create our own classes of
exceptions can be found in the online documentation for Delphi. The original or the new
style guide has no mention of how we name classes of exceptions, but the documentation
uses descriptive names for classes inherited from the Exception class, and all inherited
classes are simply prefixed with "E", e.g., EMathError or EUnderflow etc. Most other
languages use a naming convention that adds the word "Exception" to the class, e.g.
MathErrorException or UnderflowException etc., and it is not unlikely that we
may come across such names in various frameworks available for Delphi.
If we throw our own exception message, then we should also write descriptive messages
with proper punctuation. The message must be understood by anyone who needs to read
what has happened and must describe the problem accurately and provide relevant infor-
mation, for example:
"Unable to connect to database. The specified credentials are incorrect."

Functions and Procedures


The original style guide does not have a section on functions and procedures, and the sec-
tion in the new style guide is primarily about global functions and procedures. The team
at Embarcadero perhaps felt the need to emphasize that there is no indentation when de-
claring a function or procedure, as opposed to declaring methods for a class and interface,
even though it is true for all types the indentation in their implementation is the same.
Most declare global functions and procedures with either two spaces as indentation or no
indentation at all. Although it seems logical to align declarations of functions and proce-
dures compared to declarations of classes, null indentation dates back to the earliest days
of the Pascal language, when most code was structural and code constructs were mostly
procedural. This problem does not require much effort, as Code Formatter will indent the
declarations as recommended; see e.g., the example in the Parameters section.
A function or procedure should be declared on the same line, indenting continuation lines
with double spaces if the declaration cannot be on one line. The new style guide also

90
emphasizes that each parameter is not separated for each line, and all parameters must be
listed on both the interface part and the implementation part.

Parameters
As with all control statements, parameters must be kept on the same line as the rest of a
statement, but with limited space it can be difficult to keep all parameters on the same
line. It is easy to apply rules on naming identifiers and recommended spacing between
parameters, but it can also be a task to break a statement into continuation lines.
interface

type
TMIDIMessage = LongWord;

procedure EncodeMIDIMessage(const AMsg: TMIDIMessage;


var AStatus, AData1, AData2: Byte);

implementation

procedure EncodeMIDIMessage(const AMsg: TMIDIMessage;


var AStatus, AData1, AData2: Byte);
begin
[snip]
end;
If a series of parameters cannot be written on the same line, a complete parameter (start-
ing with a modifier to include a semicolon or a closing parenthesis), or a complete set of
parameters must be kept on the same line, see the example above. The rule is simple as
parameters are separated by semicolons and each continuation line must start after a
semicolon before breaking from a line.
If a parameter or set of parameters cannot be on the same line, e.g., between a semicolon,
or the opening parenthesis and a semicolon, or between the opening and closing paren-
theses, the line must be broken after any comma or, as a last resort, by a space. Code For-
matter will try to apply those rules when it breaks lines.
As with the principles behind Refactoring, we should consider rewriting a function or
procedure if we are splitting declarations into multiple continuation lines with too many
parameters. Most developers are used to multiple parameters such as ALeft, ATop,
ARight, ABottom: Integer, and in some cases that data is simply passed in a
const ARect: TRect. This is not a big problem, unless we are working with many
edges and we need several sets of left, top, right, and bottoms, which could perhaps be
solved with some rectangles instead.

91
We can often come across old domain-specific functions and procedures, e.g., SaveCom-
pany, which perhaps once started with just a few parameters such as name, address, and
telephone. But at some point, the need for more information came, e.g., web page, email
address, etc., that affected the range of parameters. Instead of adding new parameters as
we often see, a simple declaration of a record with the information can increase readabil-
ity and reduce the complexity of an array of parameters.
And such types of records, which do not need to change the process, may at a later stage
form the basis for constructing a real class that has the final responsibility for handling
information about, e.g., a company.

with Statement
The keyword with is a controversial statement for some developers, and most develop-
ers have also experienced when maintaining constructs from early "abuse" of the lan-
guage function. It is easy to abuse with in the same way with excessive use of exceptions
blocks. They should be used wisely.
The language function was created to make it more convenient to refer to complex types
of variables, but the main concern arises when we change the scope of enclosed con-
structs of code, which can introduce errors. Not by the enclosed code, but simply by the
fact that references can change silently and disrupt the flow of execution. The problem
corresponds to changing the scope of references by rearranging the order of units in uses.
An important task for a developer is of course to control the execution, and this also in-
cludes checking the scope of all constructs. We do not introduce new identifiers into a
codebase that will affect another area, so we search the code for existing names and
scopes before choosing an appropriate name. Despite caution, it is possible to change a
reference by scope completely silent, e.g., by adding a unit, changing an inherited class, or
shadowing an identifier, or as here, simply changing the scope with a with statement.

An aversion to with statements certainly stems from an abuse of this statement in the
early years of the with function, when it was typical to see extensive scoping of, for in-
stance, components and even entire forms that pulled data from a large number of com-
ponents into database components and vice versa. These paved the way for errors, as it
was often customary to introduce new features at the level of forms that were already
heavily scoped in large parts of an application, and because it was common for forms to
just be mixed with business logic in one place, and that harmonized with the thoughts of
Rapid Application Development in the first several years. There was very little or no
views on principles in software development, such as separation of concerns and straight-
forward, basic principles in object-oriented programming.
The dislike is widespread in some groups, where the use of the with statement is dis-
couraged or completely rejected. However, we do not need to go to extremities, as the

92
recommendations can minimize the risk of introducing problems with scoping. A rule
should be to avoid scope of classes and limit the use of with statement to local code con-
structs only. It will improve the understanding of scope for even junior developers, for ex-
ample:
var
RGB: PRGBTriple;
begin
{ Convert to gray scale using NTSC formula. }
RGB^.rgbtRed := Round(RGB^.rgbtRed * 0.299 +
RGB^.rgbtGreen * 0.587 + RGB^.rgbtBlue * 0.114);
RGB^.rgbtGreen := RGB^.rgbtRed;
RGB^.rgbtBlue := RGB^.rgbtRed;

// vs.

{ Convert to gray scale using NTSC formula. }


with RGB^ do
begin
rgbtRed := Round(rgbtRed * 0.299 + rgbtGreen * 0.587 + rgbtBlue * 0.114);
rgbtGreen := rgbtRed;
rgbtBlue := rgbtRed;
end;
end;

with-statement adds an increased attention to the current formula, and a less distraction
in a repetition of the same reference. The constants can easily be declared elsewhere, but
here is a recommended and local use of a with statement that only changes the scope of
local variables – enclosed or in tight scopes. Another example could be:
var LStrings := TStringList.Create;
LStrings.CommaText := 'This a test of words.';
NumberOfWords := LStrings.Count;
LStrings.Free;

// vs.

with TStringList.Create do
begin
CommaText := 'This a test of words.';
NumberOfWords := Count;
Free;
end;

In the early years of the Delphi compiler, there was a penalty in performance with a con-
stant referencing of variables as pointers were reloaded into registers repeatedly. Perfor-
mance was often improved when three or more of the same reference could be replaced
with a with statement and the same pointer could be preloaded into a register. With
modern Delphi compilers, this improvement in performance is already achieved with
smarter versions of the compilers capable of optimizing this type of constructs. We do not
gain or lose CPU performance by omitting or using a with statement.

93
Limiting the use of with statements to local code constructs, and with references to local
variables, will not only appease the skeptics among developers, but it will also ensure that
inexperienced developers do not have to feel uncertain about the intent of an explicit
scope. On the other hand, if a team has no problems understanding scope in general, it
should, e.g., not be a problem to use inner with statements at the class level as long as
the constructs do not introduce ambiguity.
A minor annoyance with a with statement is of course the debugger's inability to derive
values when we inspect scoped identifiers. We need to add a watch with a fully qualified
identifier to inspect a value. This may set a technical constraint for many who use the
with statement if readability is not as important as the technical aspects.

Other Statements
The other statements are not in the same group as reserved words and language func-
tions, as the types of statements described above, but can greatly influence the control of
an execution. The styling may not be the big problem, as these are usually styled as usual
statements, but because they can break an execution of a block of code, a few recommen-
dations are important. Although they look like regular functions or procedures, they differ
in that they are intrinsic routines, meaning that it is the compiler that creates the correct
construction of code rather than a specific routine being called.

Exit routine
One of the most dramatic and frequently used procedures is a call to Exit, which can
also be considered bad practice because it can introduce a derailment in the execution of a
construct – especially when resetting and cleaning up used resources. There are no prob-
lems in using Exit itself, as it executes without too much trouble, but it is often possible
to refactor code constructs and avoid using an Exit routine altogether. If we really need
to use the Exit procedure, Coding Best Practice is to place the procedure first in a con-
struct, as a more obvious precondition, making it easy for anyone working with the code
to notice the conditions and a derailment, for example:
procedure TMIDIOutDevice.HandleNeeded;
begin
if FHandle <> 0 then
Exit;
if midiOutOpen(@FHandle, DeviceID, Cardinal(@mmeapiCallBack),
Cardinal(Self), CALLBACK_FUNCTION) = MMSYSERR_NOERROR then
HeadersNeeded;
end;
The above example is simple, and it will also be easy to refactor the construction in an-
other way, but the point is to use the Exit procedure as a precondition at the top of the
code block and never somewhere in the middle of a block, because it can create so-called

94
phantom breaks or exits , and not least that they can be considered traps if they are hid-
den in the middle of a construct. This approach is to ensure that a developer is not sur-
prised by an unfortunate misinterpretation of the intention of a construct and introducing
a faulty change or a typical memory leak because cleanup of resources was omitted by an
Exit procedure. The above example could be rewritten as:

procedure TMIDIOutDevice.HandleNeeded;
begin
if FHandle = 0 then
if midiOutOpen(@FHandle, DeviceID, Cardinal(@mmeapiCallBack),
Cardinal(Self), CALLBACK_FUNCTION) = MMSYSERR_NOERROR then
HeadersNeeded;
end;
In development environments, the advantages, and disadvantages of Coding Best Prac-
tices, such as the single-exit-point principle, are often discussed, which sometimes may
well be difficult to transfer to Object Pascal. In other programming, the discussions often
boil down to the fact that execution of a function ends when a return value is set - as in an
Exit. Therefore, the discussions are more significant in those languages, in contrast to
Object Pascal, where we can set Result repeatedly in the process, so the discussions
here are more obviously on preferences rather than practical approaches. The following
function will, for instance, not be possible in many other languages:
Result := False;
if A <> 0 then
Exit;
Result := True;
Discussions about single-entry-point and single-exit-point principles have become a little
more nuanced today with modern programming languages, so it makes more sense to fo-
cus on recommending where we should use Exit when we find a need for the function.
The above example could just as well be:
if A = 0 then
Result := True
else
Result := False;
If we save an overhead of 2 bytes in one of the examples, it may seem like an unimportant
detail to most people, but it makes a world of difference if we have a requirement to com-
ply with 1 ms in response time, which we must live up to. Similarly, it need not matter
whether we use A = 0 or A <> 0 if we have several million nodes to check through.
Then even the smallest overhead can mean the world for a slightly heavier response time.
Such considerations can be of great importance for a construction if the following con-
flicts with readability, but has the greatest performance gain:
Result := A = 0;

95
If an Exit statement is called inside a try/finally block, a finally part of the
block will be executed, and it will not in that respect break a protection in reset or cleaning
up of resources.

Break, Continue, and other routines


The Break procedure is difficult to omit without executing unnecessary code, since the
idea is to stop further execution if a condition is met. Unlike the Exit procedure, which
jumps out from a current procedure and regardless of whether it is in the middle of a code
block, e.g., loops, then Break jumps out from a current code block, and stops e.g., for,
while, and repeat statements from continuing their loop.

The Continue procedure, like the Exit procedure, can be considered a refactoring sub-
ject, as it may be possible to rewrite code constructs that use the Continue procedure.
This procedure is mostly used to omit large parts of code blocks when certain conditions
are met, and no further actions are required. In that case, the loop can be activated to con-
tinue on the next step. But the fact that it is widely used to omit large parts of a block of
code is perhaps the problem that should be refactored into smaller blocks of code.
The reason behind the various disputes in using these types of procedures is to be found
in their similarities to the infamous goto, which is said to invite spaghetti code and lead
to unintended complexity in code constructs. These types of statements are mostly used
in imperative programming and unfortunately led to a tendency to develop large blocks of
code even after the introduction of procedural programming. Among other things, it was
largely the latter that became synonymous with "large procedural codes".
Although in many respects these procedures are considered traps and bad practice, these
procedures are necessary in many cases, including to increase the readability of code con-
structs. For example, we don’t want to go through all the data in a set when we've found
what we search for in the middle of the set. And again, if blocks of code have become too
large, then we should consider using the thoughts behind Refactoring instead.

Code Formatter and Statements


With the introduction of new language features, e.g., inline variables, it seems that devel-
opers at Embarcadero completely forgot to update the Code Formatter to support the new
language features.
With all the bugs that have accumulated around Code Formatter, we either have to break
with the formatter or wait a little longer to introduce new language features into our own
codebase until they are fully supported and compatibility is no longer an issue , or simply
just write code constructs stylized as recommended, which will mean that the need for
Code Formatter no longer exists.

96
Classes and Interfaces
Chapter 8
In the original style guide, the recommendations for classes were very simple, as access
levels consisted only of the original four access specifiers and arranged in a specific order.
Today, classes are much more complex and with additional access specifiers. The recom-
mendation to declare access levels in a specific order is also omitted, as it would break the
attempts to declare type definitions as class scoped public, and which we will need to refer
to for some private or protected members.
We also need to consider class members and variables, not to mention how they should
be styled in declarations of classes. The new style guide is a bit more descriptive in
explaining the styling of classes and interfaces, which is inherent behind an evolved
structure for classes and interfaces, compared to the original style guide. But there is a
basic lack of examples of how we incorporate ordinary members and class members.
Alongside the development of the structure of classes and interfaces, new modifiers are
added, attributes such as unsafe and weak are introduced, etc., and examples of how we
should style these functions are needed.

Image by xkcd.com, and licensed under a


Creative Commons Attribution-NonCom-
mercial 2.5 License.

97
Structure of a Class
The original organization of a class definition still applies, in that we do not place declara-
tions in a random order. We should first declare fields, then methods and finally proper-
ties for each access level, e.g., private, protected, public and published. The
only missing rules are when, where, and how we declare class variables, class methods,
and class properties, since the basic structure of a class is widely recognized and prac-
ticed, as it is visualizing the access level for each specifier.
Access Specifiers for private and protected have new and more "tough" counter-
parts, as they are more uncompromising in restricting access for private or pro-
tected, and thus the access level is lower than their counterparts. Although the original
rule of arranging declarations according to their access level is still widely followed, the
rule is not mentioned in the new style guide, as this rule must be broken in many cases.
TMIDIMessage = class(TObject)
strict private
private
strict protected
protected
public
published
end;
A common reason for breaking the order of access specifiers can be declarations of public
class scoped enumerations, which would also need to be referenced in declarations at
lower accessible levels, e.g., private or protected. An example could be an enumeration of
types for MIDI messages, e.g., channel voice, system common or system real-time mes-
sages. We could choose a scoped enumeration approach by turning on the
SCOPEDENUMS directive and declaring members accordingly, for example:

TMIDIMessage = class(TObject)
public type
TMessageType = (ChannelVoice, SystemCommon, SystemRealTime);
private
FMessageType: TMessageType;
procedure SetMessageType(const AValue: TMessageType);
public
property MessageType: TMessageType read FMessageType;
end;
Before we go any further, we must bear in mind that any access specifier without a key-
word after a specifier, the default keyword was added completely invisibly, e.g., public
and public var are the same if no other keywords are added. This also has a big im-
pact on the styling for each access specifier, and inconsistency in styling might add confu-
sion for an inexperienced developer when we mix multiple keywords together.

98
The default var keyword for access specifiers can only be changed by adding another
keyword, e.g., const, type, procedure, function, property, etc., but the var
keyword can be re-established after using one of the other keywords, e.g., below is per-
fectly legitimate, but should be strongly discouraged:
TMIDIIDevice = class(TObject)
private
FHandle: NativeUInt;
procedure SetHandle(const AValue: NativeUInt);
var FDeviceID: NativeInt;
FDeviceName: string;
end;
Most professional developers will agree that the above example is a bit clumsy, if not aw-
ful. In such cases we will often see a different approach by defining and adding the same
access specifier, perhaps with the rationale of grouping related variables and methods to-
gether. The example below is indeed the same as the one above, but the styling is quite
different:
TMIDIIDevice = class(TObject)
private
FHandle: NativeUInt;
procedure SetHandle(const AValue: NativeUInt);
private
FDeviceID: NativeInt;
FDeviceName: string;
end;
Within each access specifier, we can declare anything in the same way that we make local
declarations between a procedure or function and its body. And Code Formatter will for-
mat anything declared with the var keyword as were they local variables, but not the
type or const keywords.

The question is, with regard to code style, and disregarding the flaws in Code Formatter,
how do we style all possible access specifiers with variations of keywords and members,
e.g., whether we write public type on the same line, considering enclosed const and
var declarations as well, or do we write access specifiers on a single line and then declare
type and const in new lines, e.g.:
TMIDIMessage = class(TObject)
public type
TMessageType = (ChannelVoice, SystemCommon, SystemRealTime);
TVoiceType = (NoteOff, NoteOn, PolyKeyPressure, ControllerChange,
ProgramChange, ChannelPressure, PitchBent);
const CDefaultMessageType = TMessageType.ChannelVoice;
var FMessageType: TMessageType;
end;

vs.

99
TMIDIMessage = class(TObject)
public
type
TMessageType = (ChannelVoice, SystemCommon, SystemRealTime);
TVoiceType = (NoteOff, NoteOn, PolyKeyPressure, ControllerChange,
ProgramChange, ChannelPressure, PitchBent);
const
CDefaultMessageType = TMessageType.ChannelVoice;
var
FMessageType: TMessageType;
end;

vs.
TMIDIMessage = class(TObject)
public type
TMessageType = (ChannelVoice, SystemCommon, SystemRealTime);
TVoiceType = (NoteOff, NoteOn, PolyKeyPressure, ControllerChange,
ProgramChange, ChannelPressure, PitchBent);
public const
CDefaultMessageType = TMessageType.ChannelVoice;
public
FMessageType: TMessageType;
end;

The first example can introduce a lot of atypical stylizations and perhaps confusion in
some cases, and while the second example appeals to a desire to structure code con-
structs, it can become disturbingly out of alignment with indentation, especially when we
start adding methods and properties. The last example seems to be a preferred approach
to the stylization of this type of construct, as it appeals to the fact that anything that is
stated explicitly also leads to less misunderstanding.
When we have a style guide that doesn't give examples of the structure of a class, we start
to draw on habits and personal preferences. As you can see, it is possible to use different
styles, and without references we have to look for the most obvious style, leaning a little
towards Coding Best Practices in similar areas.

Methods
Unlike traditional procedures and functions, methods in a class which are also procedures
and functions can be decorated with directives, e.g., binding, calling convention and
warnings. Just as declaration of a class without explicit inheritance will inherit from
TObject by default, so a method without binding will by default be static. And simi-
larly, if only the reserved word inherited is used, then the default inherited method
called will be the enclosing method with the same arguments as in the call, for example:
procedure TControl.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited;
end;

is equal to:

100
procedure TControl.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
end;

Nevertheless, it is good practice to use unambiguous references, including explicitly add-


ing inheritance to objects and methods, as it provides a better overview and e.g., reduces
misunderstandings. Furthermore, we will be able to enable smart functions such as "Find
declaration" with [Ctrl + (Left) click]. [Alt + Up Arrow] will work for the inherited
keyword without an explicit reference to a method, but it will not work for a class key-
word that does not have a reference to inheritor. By activating class completion on meth-
ods with an override binding, [Shift + Ctrl + C], only an inherited keyword is added,
and we have no option to add a full qualified reference to inherited. This results in a
tendency to leave inherited as is, as most will argue that it otherwise gives more work.

There are no rules in any of the above cases or for similar cases, except for considerations
of Coding Best Practices and that declarations of methods should be kept on the same
line, including binding, specifiers, and warnings. Any continuation lines should follow the
same rule as declaring ordinary procedures and functions with parameters as described in
the "Functions And Procedures" and "Parameters" sections of the Statements chapter.

Class Methods and Class Variables


Class methods and class variables are similar in styling to ordinary methods and varia-
bles, except of course for the reserved word class. A mix of class methods and ordinary
methods is common, and there are no rules for a definite separation of these types of
methods, just as they are also traditionally arranged in an alphabetical order with a mix of
the two types.
I modsætning til andre reserverede ord, f.eks. type, const og var, gør tilføjelsen af der
reserveret class ord før en metode ikke den næste metode til en klassemetode. Hver
klassemetode skal erklæres eksplicit med class for at det bliver til en klassemetode.
Dette gør erklæringen af klassemetoder noget nemmere, da vi nødvendigvis må være ek-
splicitte med det reserverede ord, class. Disse bemærkninger er væsentlige, fordi der er
en lille twist til class var, som vil alle efterfølgende erklæringer af variabler til klas-
sevariabler, indtil der optræder et nyt reserveret ord:
TMIDIMessage = class(TObject)
private
class var FMessageType: TMessageType;
FVoiceType: TVoiceType;
end;

101
The FVoiceType variable is a class variable, just as FMessageType will be. And to make
FVoiceType an instance variable, we need to add the reserved word var to the declara-
tion, for example:
TMIDIMessage = class(TObject)
private
class var FMessageType: TMessageType;
var FVoiceType: TVoiceType;
end;
The above language function class is often used at the end of each access specifier,
making such constructs a little less confusing compared to class methods, which can of-
ten be found among regular methods. Although not listed as a recommendation, common
practice with class variables is:
TMIDIMessage = class(TObject)
private
FVoiceType: TVoiceType;
class var FMessageType: TMessageType;
end;
The same approach is used for class properties, which are styled in the same way as regu-
lar properties, except that class properties have a few limitations compared to regular
properties. E.g., we cannot put class properties in the published section, nor can we use
stored and default specifiers, or use virtual getters and setters as an accessor must be
static. The difference between regular properties and class properties also introduces
different approaches to styling, including some methods that break the rules for aligning
access specifiers to the same indentation as the class identifier.
The different behavioral patterns of the language functions, e.g., by mixing regular decla-
rations and class declarations, could cause misplacement of variables, since the block of
variable declarations is not completed until a new reserved word appears. The style guide
has no recommendations specific to class variables or class methods, and the examples in
the Delphi documentation give, as usual, mixed signals in styling. Here we wish that Em-
barcadero could be consistent in their code examples and that they agreed with the rest of
their style guide, for example:

102
type
TMyClass = class
strict private
class var // Note fields must be declared as class fields
FRed: Integer;
FGreen: Integer;
FBlue: Integer;
public // ends the class var block
class property Red: Integer read FRed write FRed;
class property Green: Integer read FGreen write FGreen;
class property Blue: Integer read FBlue write FBlue;
end;

This example is taken from the Delphi documentation on properties in the class proper-
ties section. The example uses two-, three-, and four-space indentations that break the
double-space indentation rule and fail to align access specifiers to class identifiers in their
attempt to align each declaration vertically. Activating the Code Formatter with default
options will format the above example as:
TMyClass = class
strict private
class var // Note fields must be declared as class fields
FRed: Integer;
FGreen: Integer;
FBlue: Integer;
public // ends the class var block
class property Red: Integer read FRed write FRed;
class property Green: Integer read FGreen write FGreen;
class property Blue: Integer read FBlue write FBlue;
end;

The comments won't be necessary in real life, but the overall styling is accurate, although
we can debate whether to write strict private and class var on two lines and be
less explicit in declaring fields or write strict private class var on one line and
end the block of statements with another access specifier, or other specifiers, if necessary.
Despite the lack of recommendations in styling mixed object and class declarations and
for different access specifiers and blocks of declarations, etc., we should at least use the
general rules for the language. An abbreviated example of a declaration of a real class
could be stylized as:
TEncoding = class
strict private
class var
FANSIEncoding: TEncoding;
FASCIIEncoding: TEncoding;
FBigEndianUnicodeEncoding: TEncoding;
FUnicodeEncoding: TEncoding;
FUTF7Encoding: TEncoding;
FUTF8Encoding: TEncoding;
class destructor Destroy;
class function GetANSI: TEncoding; static;
class function GetASCII: TEncoding; static;
class function GetBigEndianUnicode: TEncoding; static;
class function GetDefault: TEncoding; static; inline;
class function GetUnicode: TEncoding; static;

103
class function GetUTF7: TEncoding; static;
class function GetUTF8: TEncoding; static;
strict protected
FIsSingleByte: Boolean;
FMaxCharSize: Integer;
function GetByteCount(Chars: PChar; CharCount: Integer): Integer; ... virtual; abstract;
function GetBytes(Chars: PChar; CharCount: Integer; Bytes: PByte;
ByteCount: Integer): Integer; overload; virtual; abstract;
function GetCharCount(Bytes: PByte; ByteCount: Integer): Integer; ... virtual; abstract;
function GetCodePage: Cardinal; virtual;
function GetEncodingName: string; virtual;
function GetMIMEName: string; virtual;
public
function Clone: TEncoding; virtual;
class procedure FreeEncodings;
class function IsStandardEncoding(AEncoding: TEncoding): Boolean; static;
function GetByteCount(const Chars: Char): Integer; overload; inline;
function GetByteCount(const Chars: array of Char): Integer; overload;
function GetBytes(const Chars: Char): TBytes; overload; inline;
function GetBytes(const Chars: array of Char): TBytes; overload;
function GetCharCount(const Bytes: array of Byte): Integer; overload;
function GetCharCount(const Bytes: TBytes): Integer; overload; inline;
function GetChars(const Bytes: array of Byte): TCharArray; overload;
function GetChars(const Bytes: TBytes): TCharArray; overload; inline;
class function GetEncoding(CodePage: Integer): TEncoding; overload; static;
class function GetEncoding(const EncodingName: string): TEncoding; overload; static;
function GetMaxByteCount(CharCount: Integer): Integer; virtual; abstract;
function GetMaxCharCount(ByteCount: Integer): Integer; virtual; abstract;
function GetPreamble: TBytes; virtual; abstract;
function GetString(const Bytes: TBytes): string; overload; inline;
function GetString(const Bytes: TBytes; ByteIndex, ByteCount: Integer): string; overload;
function GetString(const Bytes: array of Byte): string; overload;
class property ANSI: TEncoding read GetANSI;
class property ASCII: TEncoding read GetASCII;
property CodePage: Cardinal read GetCodePage;
property EncodingName: string read GetEncodingName;
property MIMEName: string read GetMIMEName;
property IsSingleByte: Boolean read FIsSingleByte;
end;

The example is very shortened, but it shows the approach of declaring blocks of class var-
iables with additional indentation, but having a mixture of object and class methods, and
still maintaining an alphabetical order of methods, as well as declaring properties at the
end of an access level. This approach is likely to be the most practiced approach. Another
less common approach is the more explicit declarations of all variables, like each declara-
tion of a method. Below we also find a shortened example from real life, and although it is
a record, the function in the language is the same:
TOSVersion = record
public type
TArchitecture = (arIntelX86, arIntelX64, arARM32, arARM64);
TPlatform = (pfWindows, pfMacOS, pfiOS, pfAndroid, pfWinRT, pfLinux);
public const
AllArchitectures = [arIntelX86, arIntelX64, arARM32, arARM64];
AllPlatforms = [pfWindows, pfMacOS, pfiOS, pfAndroid, pfWinRT, pfLinux];
private
class var FArchitecture: TArchitecture;
class var FBuild: Integer;
class var FMajor: Integer;
class var FMinor: Integer;
class var FName: string;
class var FPlatform: TPlatform;
class var FServicePackMajor: Integer;
class var FServicePackMinor: Integer;
class constructor Create;

104
public
class function Check(AMajor: Integer): Boolean; overload; static; inline;
class function Check(AMajor, AMinor: Integer): Boolean; overload; static; inline;
class function ToString: string; static;
class property Architecture: TArchitecture read FArchitecture;
class property Build: Integer read FBuild;
class property Major: Integer read FMajor;
class property Minor: Integer read FMinor;
class property Name: string read FName;
class property Platform: TPlatform read FPlatform;
class property ServicePackMajor: Integer read FServicePackMajor;
class property ServicePackMinor: Integer read FServicePackMinor;
end;

An access specifier is added to each type of declaration, e.g., public type and public
const, and each class variable is declared with class var, as is each declared class
function and class property.

Both examples above are acceptable because they are commonly practiced and because
there are no explicit recommendations about rules in the style guide. Both introduce a
good stylization of class methods and class variables, except that the last example would
be closer to Coding Best Practices with explicit declarations. A specific stylization should
be formalized within a company, project, or team, and as with any other stylization, it is
important to have a consistent style as in one of the examples.
If you are not familiar with class methods or class variables then it is recommended to
consider this language feature as it can help us to remove global procedures, functions
and variables which as mentioned before are considered bad practice.

Interfaces
Although interfaces may be exotic, they remain simple in their stylization as simple class
definitions. We cannot use access specifiers or declare field variables, nor specify class
methods or class variables, or use binding. The description in the new style guide should
be sufficient and covers basic constructions of interfaces, for example:
type
IStreamPersist = interface
['{B8CD12A3-267A-11D4-83DA-00C04F60B2DD}']
procedure LoadFromStream(Stream: TStream);
procedure SaveToStream(Stream: TStream);
end;
Vi kan måske blot tilføje at identifiers for parametre som i ovenstående konstruktion ikke
behøver at være de samme navne, når interfacet skal implementeres for en class, f.eks.:
TDataStream = class(TInterfacedObject, IStreamPersist)
public
procedure LoadFromStream(AStream: TStream);
procedure SaveToStream(AStream: TStream);
end;

105
We cannot change the name of the methods and we cannot specify const or var for the
implementation of the methods once the interface is defined.

Other Topics
The description of the other topics covered by "Type Declarations" in the new style guide
should be sufficient. And especially the section on "Anonymous Method Types" should be
worth studying, as it can introduce differences in approaches to these types of code con-
structions with procedures enclosed in parentheses, for example:
ForEachOutputParameter(ProxyMethod,
procedure(Param: TDSProxyParameter)
begin
if Param.ParameterDirection = TDBXParameterDirections.ReturnParameter then
R := Param;
end);

It is also mentioned in the new style guide that anonymous methods constructs are used
inconsistently throughout the Delphi library, which is the risk taken when a stylization
with new language features is not presented and/or the documentation is inconsistent re-
garding to give examples of a language function.

Compiler Attributes
Another topic not covered by the new style guide is compiler attributes, but the documen-
tation on attributes does provide a few examples. For all attributes, spaces are placed on
both sides of the attribute, but not on the left side, if they are indented or enclosed in pa-
rentheses as first, and no spaces are added inside the parentheses.

[Ref] Attribute
The [Ref]attribute solves a problem with constant values passed in parameters, as dif-
ferent types of values can be loaded into registers and not as a reference in the form of a
pointer. We can either use the [Ref]attribute before or after the const keyword, as the
documentation doesn't explain a difference:
TMIDIMessage = class(TObject)
class procedure Decode(const [Ref] Msg: LongWord;
var Status, Data1, Data2: Byte); inline;
end;
or:
TMIDIMessage = class(TObject)
class procedure Decode([Ref] const Msg: LongWord;
var Status, Data1, Data2: Byte); inline;
end;

106
Unfortunately, Code Completion has an error when activated after the declaration. The
definition of the method in the implementation is missing the [Ref] attribute, causing
the compiler to complain about the difference. We need to add the attribute manually.

[Unsafe] Attribute
The [Unsafe] attribute can be applied to field variables as well as class variables. Alt-
hough we cannot find any examples of its use, the common stylization of this attribute in
the Delphi library is as follows:
private
[Unsafe] FController: IInterface;

Unlike the [Ref] attribute, the [Unsafe] attribute is highlighted in the editor as a key-
word. And unfortunately, Code Formatter tends to format the attribute as:
private
[Unsafe]
FController: IInterface;

[Volatile] Attribute
The [Volatile] attribute is usually stylized as:

strict private
[Volatile] FHeadIndex: Integer;

Unfortunately, Code Formatter has a problem with the [Volatile] attribute, as it will
format the above stylization to:
strict private[Volatile]
FHeadIndex: Integer;

The attribute will be formatted like the previous attribute if a strict keyword is omit-
ted.

[Weak] Attribute
The [Weak] attribute is perhaps the most used attribute of them all, and is usually styl-
ized like the previous two attributes:
private
[Weak] FResponse: TCustomRESTResponse;

Unfortunately, Code Formatter again has a problem with the [Weak] attribute, as it will
format the above stylization to:

107
private
[Weak]
FResponse: TCustomRESTResponse;

108
Chapter 9
Code Formatter
We have discussed the Code Formatter in the previous chapters, and in many cases de-
scribed the inconsistencies between the formatting and the recommended stylization of
code constructs. However, the function is not always bad. The idea of formatting code is
of course to adapt the stylization of the source code to not only a standard style guide, but
also to a formal coding style within a company, which should be able to be satisfied with
the available options in Code Formatter.
Not all areas of styling are covered by Code Formatter, and most options may need to be
set specifically to "As is", so we must write code manually exactly as recommended in a
formalized style guide. Although most professionals write code according to a style guide
and do not need to activate a tool, the function can be practical in many situations.
It cannot only be used on "other people's bad code", e.g., arbitrary style, it can also prove
beneficial in various constructs. If a team is expected to follow the requirements of a com-
pany, e.g., a standard style guide, Code Formatter can be used to format a code block to a
more personal style by switching to a private profile, make changes, and then activating
Code Formatter for the code block with a standard profile or a profile for the company, so
to speak correct stylization before the changes are committed for review.
For example, some would prefer to declare constants with a vertically aligned indent after
the equal sign ("="), although the standard style guide generally discourages such verti-
cally aligned indents. Mainly because maintaining vertical alignments, without taking
into account left indentation, doesn't offer any particular benefits in terms of readability.
That's not to say that vertical alignments can't be valuable for creating an overview of a
construct, and Code Formatter can actually help add and remove vertical alignments as
needed, for a single block of code or for an entire file.
The disadvantage of this function is that there is only the option of a strict adjustment for
all constants or to remove all adjustments. There are, e.g., no option for "As is".

Profiles
Delphi comes with three profiles with different settings, but the manual does not provide
a summary of the difference between the three profiles. A complete list of all items and
their settings in all three profiles is provided below, highlighting the slight differences

109
between the profiles. The following sections will review the main groups and describe
each option with examples if necessary:
INDENTATION Default profile Compact profile Wide profile
1.1 General
1.1.1 Continuation indent 2 2 2
1.1.2 Do not indent after position 40 40 40
1.1.3 Indent assembly sections True True True
1.1.4 Indent Begin and End keywords False False False
1.1.5 Indent blocks between Begin and End True True True
1.1.6 Indent class definition bodies False False True
1.1.7 Indent comments Yes Yes Yes
1.1.8 Indent compiler directives False False False
1.1.9 Indent function bodies False False True
1.1.10 Indent inner functions True True True
1.1.11 Indent interface, implementation, and other sections False False False
1.1.12 Indent nested brackets and parentheses False False False
1.2 Indentation for case statements
1.2.1 Indent case contents True True True
1.2.2 Indent case labels True False False
1.2.3 Indent Else in case statements False False True
1.3 Indentation for labels
1.3.1 Indent labels Dec. one indent Dec. one indent Dec. one indent

SPACES Default profile Compact profile Wide profile


2.1 General
2.1.1 Set spacing around colons After only After only Before and after
2.1.2 Set spacing around colons in format None None None
2.1.3 Set spacing around commas After only After only After only
2.1.4 Set spacing around semicolons After only After only After only
2.1.5 Spaces before parentheses in functions No No No
2.2 Set spacing for comments
2.2.1 Set spacing for // comments Before and after Before and after Before and after
2.2.2 Set spacing for { and (* comments Inner and outer Inner and outer Inner and outer
2.3 Set spacing for operators
2.3.1 Set spacing around assignment operators Before and after Before and after Before and after
2.3.2 Set spacing around binary operators Before and after Before and after Before and after
2.3.3 Set spacing around unary prefix operators None None Before and after
2.4 Set spacing for parentheses and brackets
2.4.1 Set spacing for parentheses False False True
2.4.2 Set spacing for square brackets False False True
2.4.3 Set spacing inside angle brackets in generics False False True
2.5 Spacing conflicts
2.5.1 Resolve space conflicts as Space Space Space

LINE BREAKS Default profile Compact profile Wide profile


3.1 General
3.1.1 Keep user line breaks False False False
3.1.2 Line break characters Default of system Default of system Default of system
3.1.3 Right margin 80 80 80
3.1.4 Trim source True True True
3.2 Insert line breaks
3.2.1 Line break after label Yes No No
3.2.2 Line break inside "Else If" False False False
3.2.3 Line breaks after semicolons True True True
3.2.4 Line breaks after Uses keywords As is No Yes
3.2.5 Line breaks before Then False False True
3.2.6 Line breaks in Anonymous Function assignments False False True
3.2.7 Line breaks in Anonymous Function usage True False False
3.2.8 Line breaks in array initializations Yes Yes Yes
3.2.9 Line breaks in Inheritance lists No No No
3.2.10 Line breaks in Labels, Export, Requires, Contains clauses As is No Yes
3.2.11 Line breaks in Property declarations False False True
3.2.12 Line breaks in Uses clauses As is No Yes
3.2.13 Line breaks in Var and Const sections Yes No No
3.2.14 Remove line breaks inside "End Else Begin" False True True
3.2.15 Remove line breaks inside "End Else If" False True True
3.3 Insert line breaks for Begin and Single instructions
3.3.1 Line breaks after Begin Yes Yes Yes
3.3.2 Line breaks after Begin in control statements Yes Yes Yes
3.3.3 Line breaks after Begin in method definitions Yes Yes Yes
3.3.4 Line breaks before Begin in control statements Yes No No
3.3.5 Line breaks before single instructions in control statements Yes No No
3.3.6 Line breaks before single instructions in try-except blocks Yes No No
3.4 Line breaks in functions
3.4.1 New line for a function return type No No No
3.4.2 One parameter per line in function calls No No No
3.4.3 One parameter per line in function definition No No Yes
3.5 Number of empty lines
3.5.1 Max number of adjacent empty lines 1 1 1
3.5.2 Number of empty lines around compiler directives 0 0 0
3.5.3 Number of empty lines around section keywords 1 1 1
3.5.4 Number of empty lines as separator in implementation sect. 1 1 1

110
3.5.5 Number of empty lines as separator in interface section 1 1 1
3.5.6 Number of empty lines before subsections 1 1 1
3.5.7 Number of empty lines before Type keyword 1 0 0
3.5.8 Number of empty lines before visibility modifiers 0 0 0

CAPITALIZATION Default profile Compact profile Wide profile


4.1 General
4.1.1 Capitalization of compiler directives UPPER CASE UPPER CASE UPPER CASE
4.1.2 Capitalization of numbers UPPER CASE UPPER CASE UPPER CASE
4.1.3 Capitalization of other words As first occurrence As first occurrence As first occurrence
4.1.4 Capitalization of reserved words and directives As is As is As is

ALIGNMENT Default profile Compact profile Wide profile


5.1 Alignment cases
5.1.1 Align "=" in constants False False False
5.1.2 Align "=" in initializations False False False
5.1.3 Align "=" in type declarations False False False
5.1.4 Align assignment operators False False False
5.1.5 Align end-of-line comments False False False
5.1.6 Align fields in properties False False False
5.1.7 Align type names False False False
5.1.8 Align types of parameters False False True
5.2 General
5.2.1 Align ":" before type names False False True
5.2.2 Alignment maximum column 60 60 60
5.2.3 Maximum unaligned lines 0 0 0

Indentation
As in many programming languages, an indentation style is a convention that governs
the indentation of blocks of code to present a structure in constructs and for entire pro-
grams, which is why indentation style is also seen as part of a coding style. Standard in-
dentation practiced in the Pascal language is similar to the Allman style, which places the
keyword begin on the following line and indents to the same level as a control state-
ment. The enclosed block of code is indented one level until the end keyword, which is
again indented to the same level as the begin keyword.

The advantages of the style are that the indented code block is clearly separated from an
enclosing statement, and it is easy to find a pair with begin and end, just as the code
block is defined by a control statement. Commenting out, removing a control statement
or block of code, or refactoring the code will be easier without, e.g., a dangling end of a
block of code, for example:
procedure SetPosition(AValue: Integer);
begin
// if AValue <> FPosition then begin
FPosition := AValue;
Changed;
end;
end;

1.1 General
The common indentation of code written in Object Pascal has always followed the two-
space rule. The setting of the two spaces for the general indentation is not found in the
Code Formatter settings, but in the "User Interface > Editor > Language" settings and in
the "Block indent" field under options. Even more significantly, this option is used during
automatic indentation and Code Completion.

111
1.1.1 Continuation indent
"Defines additional indent that is added for continuation lines when an expression is con-
tinued on several lines."
A statement, declaration, list of values, etc., that for various reasons will require more
than one line, may continue on the next line. The first line is a broken line, and subse-
quent lines are continuation lines, and these continuation lines are indented by a number
of spaces specified by this option. Technically, a line can have a length limited only by the
IDE, compiler, and the system, but in stylization, continuation lines are inserted by Code
Formatter if a line exceeds a right margin set in the "Line breaks" section under the "Gen-
eral ". The right margin is set to 80 characters by default.
The default setting for continuation line indentation is 2. The recommended indentation
is two spaces; thus, continuation lines are indented one level using the two spaces, for ex-
ample:
class function GetString(Locale: TLocaleID; LocaleItem, DefaultIndex: Integer;
const DefaultValues: array of Pointer): string; static;

Note: This option should not be confused with a regular indentation, as it also usually
consists of two spaces. There is no setting for the regular indent under the Code Format-
ter settings, as it must be found in the setting under "User Interface > Editor > Language
> Options" in a "Block indent" edit box and is set to 2 spaces by default.

1.1.2 Do not indent after position


"Defines maximum width of indent, which can be inserted by the formatter."
The default value is 40 spaces, which equals 20 indentation levels, starting from the left
margin. That should be more than enough. If we did indeed exceed the 40 spaces, then
we should seriously consider refactoring the code construction to a more acceptable level
of indentation. There is no recommended limit for levels of indents, but 5 to 8 levels
should be sufficient, and that is from the first indentation, not the left margin. However,
some recommendations will go even further and say that if we need more than 3 levels,
then we should consider rewriting the code. This can be in relation to indentations of 4 or
8 spaces, and where we can quickly run out of space.
Some types of code constructs naturally require a lot of indentation, and a satisfactory
level of indentation should be for the sake of readability.

1.1.3 Indent assembly sections


If "True", indent assembler sections as usual code:

112
procedure ConvertAddr;
asm
TEST EAX,EAX
JE @@Exit
SUB EAX,$1000
@@Exit:
end;
If "False", indents in assembler sections should be as set:
procedure ConvertAddr;
asm
TEST EAX,EAX
JE @@Exit
SUB EAX,$1000
@@Exit:
end;
Although inline assembly code has only one level of indentation, the original or the new
style guide has no mention of the number of spaces in an indentation level, e.g., until up-
codes or between upcodes and operands. Code Formatter indents inline assembly code
after the "Block indent" setting, default with 2 spaces, enclosed by the keywords asm and
end.

Although assembly code is indented as regular blocks of code that align upcodes relative
to the code block, inline assembly code is traditionally indented 8 spaces from the asm
keyword, and they are also usually vertically aligned to operands by 8 spaces from a verti-
cal alignment of upcodes . The inline assembler in Delphi's library is mainly formatted in
this way, but we may come across individual indentations that deviate from the tradi-
tional indentation of upcodes and operands. Code Formatter uses the "Block indent" set-
ting and does not change the spacing between upcodes and operands and will always re-
main as it is - as they were "As is".
Note: If a procedure with a block of assembly code is constructed as an inner procedure or
function of another, the body of the outer procedure or function will be aligned to the
block of assembly code, which is obviously an error.
If we have set an option in "Capitalization of other words" to "As first occurrence", and an
upcode could look like "a first occurrence" of any identifier, e.g., if TEST instruction is pre-
sent, then any subsequent identifiers will be capitalized as in upcode. That is a local varia-
ble named "Test" will be changed to "TEST", which of course is also an error.
Although using inline assembler is rare, we need to be aware of the above errors and not
save unintended changes in the code such as the spaces between assembler code and re-
maining codes in a file.
There are no separate recommendations in aligning inline assembly code, other than reg-
ular indentation with 2 spaces. Tab indentation has been the practice of indentation since

113
the earliest history of assembly language, and tabs are usually aligned equal to 8 spaces.
Thus, 8 spaces have also been normal practice for indenting upcodes and in a vertical
alignment of operands and should have been the recommended indentation. However,
this will be incompatible with Code Formatter.
Although using labels is discouraged in Object Pascal, using labels in assembly code is a
whole different story. Labels are integral parts of code constructions in assembly language
and impossible to avoid, unless you have the courage to calculate absolute or relative ad-
dresses yourself at all the places you want to jump from and to. Labels are usually aligned
with the asm keyword and declared alone on one line.

Another problem is spaces between operands, e.g., after a comma. Some omit the space
after a comma, others use a mixture of no space and a space before an identifier, but most
formal x86 assembler style guides will recommend a space after a comma. Most of the as-
sembly code in the Delphi library consists of a space after a comma and thus perhaps
should have been the recommended style as well.
A third problem is the practice of capitalizing upcodes and operands, and the normal styl-
ization of assembly code in the Delphi library is capitalization for both upcodes and oper-
ands, as well as Pascal Case for all identifiers. Thus, the above example will be stylized as:
procedure ConvertAddr;
asm
TEST EAX, EAX
JE @@Exit
SUB EAX, $1000
@@Exit:
end;
The assembler language also has its own Coding Best Practices and standard recommen-
dations for stylization, which could probably be worth a study, but are superficially de-
scribed in this section, because Code Formatter has a few options for inline assembler in
Object Pascal. In addition, recommendations about descriptive and meaningful identifiers
should also apply to labels in inline assembler.

1.1.4 Indent Begin and End keywords


If "True", the keywords begin and end must be indented:

if I > -1 then
begin
Index := I;
end;
"False" is the default setting.
Indentation of the keywords is not the recommended indentation, but it can be enforced
by Code Formatter. This indentation would of course increase the number of indentation

114
levels considerably and could easily break any recommendations to limit indentation lev-
els.
Another issue is "Auto indent mode" and Code Completion does not support indentation
of the begin and end keywords when set to "True".

1.1.5 Indent blocks between Begin and End


If "True", the contents of a block between begin and end must be indented:

if I > -1 then
begin
Index := I;
end;
If "False", block content should not be indented between begin and end:

if I > -1 then
begin
Index := 3;
end;
"True" is the default setting and the recommended indentation of code blocks between
begin and end keywords

1.1.6 Indent class definition bodies


If "True", then additional indentation must be inserted for sections ("var", "const", visibil-
ity) in a class definition. Members before the first section are always indented:
type
TMIDIDevice = class(TObject)
FHandle: NativeUInt;
public
property Handle: NativeUInt read FHandle;
end;
If "False", head elements of a class definition must be indented at the same level as the
name of the class:
type
TMIDIDevice = class(TObject)
FHandle: NativeUInt;
public
property Handle: NativeUInt read FHandle;
end;
The default setting is "False".
If "True", the main elements of the definition will be indented one level, except for any
declarations immediately following the declaration of the class and we have not yet speci-
fied any access specifiers. Identifiers will subsequently be adjusted according to access

115
specifiers. If an access specifier is specified just after the declaration of the class, all identi-
fiers will be indented as usual between access specifiers, and the difference would be that
the access specifiers are indented and not aligned with the name of the class, e.g.:
type
TMIDIDevice = class(TObject)
private
FHandle: NativeUInt;
public
property Handle: NativeUInt read FHandle;
end;

1.1.7 Indent comments


If "Yes", then comments must be indented as regular statements:
begin
{ This is a
block comment }
// This is a line comment
FPosition := AValue;
end;
vil blive:

begin
{ This is a
block comment }
// This is a line comment
FPosition := AValue;
end;
If "With additional indent" is selected, comments are further indented:
begin
{ This is a
block comment }
// This is a line comment
FPosition := AValue;
end;
If "No", then the positions of comments will not be changed.
Default is "Yes" and should be the recommended setting.

1.1.8 Indent compiler directives


If "True", compiler directives are indented as with regular statements, e.g., indented to the
current indentation level:

116
if AValue <> FPosition then
begin
{$IFNDEF Debug}
FPosition := AValue;
{$ENDIF}
end;
If "False", then all compiler directives are placed in the left margin:
if AValue <> FPosition then
begin
{$IFNDEF Debug}
FPosition := AValue;
{$ENDIF}
end;
Note: Inline compiler directives are placed "As is":
PathDelim = {$IFDEF MSWINDOWS} '\'; {$ELSE} '/'; {$ENDIF}

Default is "False", and although not specifically mentioned in the style guide, compiler di-
rectives are traditionally left margin aligned, except for inline compiler directives.

1.1.9 Indent function bodies


If "True", other parts of functions and procedure are indented:
procedure SetPosition(AValue: Integer);
var
LValue: Integer;
begin
LValue := EnsureRange(AValue, 0, 100);
if LValue <> FPosition then
FPosition := LValue;
end;
If "False", then other parts of functions and procedure are not indented:
procedure SetPosition(AValue: Integer);
var
LValue: Integer;
begin
LValue := EnsureRange(AValue, 0, 100);
if LValue <> FPosition then
FPosition := LValue;
end;
Default is "False" and is the recommended indentation and setting.

1.1.10 Indent inner functions


If "True", code of child functions and procedures is indented relative to the code of the
main function or procedure:

117
procedure SetPosition(AValue: Integer);
function IsDifferent: Boolean;
begin
Result := AValue <> FPosition;
end;
begin
if IsDifferent then
FPosition := AValue;
end;
If "False", inner functions and procedures are aligned to the outer function or procedure:
procedure SetPosition(AValue: Integer);
function IsDifferent: Boolean;
begin
Result := AValue <> FPosition;
end;
begin
if IsDifferent then
FPosition := AValue;
end;
The default setting is "True" and will also be the recommended indentation of underlying
functions and procedures.

1.1.11 Indent interface, implementation, and other sections


If "True", the contents of sections must be indented after the interface, implemen-
tation, initialization, and finalization keywords:

interface

type
TMIDIDevice = class(TObject)
procedure HandleNeeded;
end;

implementation

procedure TMIDIDevice.HandleNeeded;
begin
if FHandle = 0 then
AllocateHandle;
end;

end.
If "False", then further indentation of the sections is omitted:

118
interface

type
TMIDIDevice = class(TObject)
procedure HandleNeeded;
end;

implementation

procedure TMIDIDevice.HandleNeeded;
begin
if FHandle = 0 then
AllocateHandle;
end;

end.
Default is "False" and is the recommended section indentation.

1.1.12 Indent nested brackets and parentheses


If "True", additional continuation line indentation is required against each nested [ ] pa-
rentheses and ( ) parentheses:
Move(P^, Dest^,
(Src - P - 1 +
EndSuffix) *
SizeOf(Char));
If "False":
Move(P^, Dest^,
(Src - P - 1 +
EndSuffix) *
SizeOf(Char));
Default is "False", and will follow the recommended indentation of continuation lines, as
there is no separate mention of additional indentation if lines are broken within nested
parentheses.
The first example with the setting "True" shows three levels of indentation, as the first is
the result of indentation for a broken line, and the second line is the result of the brackets
in the Move procedure as well as the nested brackets, e.g., additional indentation for bro-
ken line and a continuation line. The last line is a result of the brackets of the Move proce-
dure and broken lines.
The last example is the regular indentation of continuation lines, and no indentation is
added regardless of nested parentheses.

119
1.2 Indentation for case statements
It's not like case statements have special indentation rules but constructs with case state-
ments can easily contain multiple levels of indentation, especially if we use a special in-
dentation style.

1.2.1 Indent case contents


If "True", blocks of case statements (after case labels) are indented relative to the case la-
bels:
case WindowsState of
wsNormal:
WindowsState := wsMaximized;
wsMinimized:
WindowsState := wsNormal;
else
WindowsState := wsMinimized;
end;
If "False":
case WindowsState of
wsNormal:
WindowsState := wsMaximized;
wsMinimized:
WindowsState := wsNormal;
else
WindowsState := wsMinimized;
end;
Default is "True", which is the recommended setting, but thus could introduce at least
three levels of indentation for a construct of case statements.

1.2.2 Indent case labels


If "True", case labels are indented relative to the keyword case:
case WindowsState of
wsNormal:
WindowsState := wsMaximized;
wsMinimized:
WindowsState := wsNormal;
else
WindowsState := wsMinimized;
end;
If "False":

120
case WindowsState of
wsNormal:
WindowsState := wsMaximized;
wsMinimized:
WindowsState := wsNormal;
else
WindowsState := wsMinimized;
end;
Default is "True" and is also the recommended setting. If set to "False", Code Formatter
will introduce another error which will reduce the indentation level of an else keyword if
used. However, it can be properly adjusted by setting the next option to "True", which will
indent the same else keyword and code block.

1.2.3 Indent Else in case statements


If "True", extra indentation is inserted for else in case statements (indent else as case la-
bels):
case WindowsState of
wsNormal:
WindowsState := wsMaximized;
wsMinimized:
WindowsState := wsNormal;
else
WindowsState := wsMinimized;
end;
If "False", align else with the same indentation as keyword case:

case WindowsState of
wsNormal:
WindowsState := wsMaximized;
wsMinimized:
WindowsState := wsNormal;
else
WindowsState := wsMinimized;
end;
The default setting is "False", which is the recommended setting. Setting this option to
"True" will also affect the previous setting and thus can be used in combination.

1.3 Indentation for labels


Labels are very rarely used in Object Pascal and should be discouraged altogether, as it
would be considered bad practice, especially on the grounds that the language feature in-
vites spaghetti code. Nevertheless, labels can be found in Object Pascal code and are still
supported in the language primarily for compatibility reasons.

1.3.1 Indent labels


Defines indentation of labels:

121
If "To left margin", labels should be aligned vertically to the far left:
procedure Test;
label Done;
begin
goto Done;
Done:
Exit;
end;
If "Decrease on indent", labels are placed one indent less than the current indentation
level:
procedure Test;
label Done;
begin
goto Done;
Done:
Exit;
end;
If "None", labels are indented to the same current indentation level:
procedure Test;
label Done;
begin
goto Done;
Done:
Exit;
end;
Default is "Decrease on indent". There is no recommended setting and there is no men-
tion of labels in either the original or the new style guide. The recommendation must
therefore be to avoid using labels.

Spaces
Space settings are not for all kinds of so-called white spaces. For instance, they do not in-
clude blank lines, but primarily spaces around operators and symbols, and not spaces
used for indentation. Along with a few of the line break options for blank lines in the next
section and most of the spacing options in this section will be able to cover what could be
considered white spaces mentioned in the "White Space Usage" chapter of the new style
guide.

2.1 General
White spaces in this section are horizontal white spaces around operators and symbols,
and specifically do not include vertical white spaces.

122
2.1.1 Set spacing around colons
Defines spaces around colon ":". The symbol is used in several ways, most notably to sep-
arate type declarations from the type, including the return value of functions.
If "None", no spaces should be inserted. Spaces before and after colons will be removed so
there are no spaces around a colon, for example:
Text:string;

If "Before only", a space is inserted after each colon. Additional spaces before and after the
colon will be removed, leaving or adding a missing space before the colon, for example:
Text :string;

If "After only", a space is inserted after each colon. Additional spaces before and after the
colon will be removed, leaving or adding a missing space after the colon, for example:
Text: string;

If "Before and after", a space is inserted both before and after each colon. Any additional
spaces before and after the colon will be removed, and any missing spaces before and af-
ter the colon will be added, for example:
Text : string;

If "Preserve spacing", a single space is preserved before and/or after a colon if a number
of spaces already exist in the code. Otherwise, no spaces are inserted, for example:
Text : string;

becomes:
Text : string;

The default setting is "After only" and is also the recommended setting.
See also "Set spacing around colons in format".

2.1.2 Set spacing around colons in format


Defines spaces around colon ":" in formatting parameters (in Write, Writeln):

If "None", no spaces should be inserted. Spaces will be removed around the colon, for ex-
ample:
Writeln(TextFile, 'Value is: ', Value:8:2);

If "Before only", one space is inserted after the colon. Multiple spaces before the colon are
removed except for one, and otherwise a missing space is added, e.g.:
Writeln(TextFile, 'Value is: ', Value :8 :2);

123
If "After only", one space is inserted after the colon. Multiple spaces after the colon are re-
moved except for one, and otherwise a missing space is added, e.g.:
Writeln(TextFile, 'Value is: ', Value: 8: 2);

If "Before and after", a space is inserted before and after a colon. Multiple spaces will be
removed, and missing spaces will be added, for example:
Writeln(TextFile, 'Value is: ', Value : 8 : 2);

If "Preserve spaces", a space is inserted before and/or after a colon if one or more spaces
exist. Otherwise, no spaces are inserted:
Writeln(TextFile, 'Value is: ', Value: 8 :2);

becomes:
Writeln(TextFile, 'Value is: ', Value: 8 :2);

The default setting is "None", and there are no recommendations mentioned anywhere,
but the default is the most practiced stylization.

2.1.3 Set spacing around commas


Defines spaces around commas ",". The comma is used, i.e., to separate parameters and
arguments and is presumably adapted from the world of mathematics for most program-
ming languages.
If "None", no spaces should be inserted. All spaces before and after the comma will be re-
moved, for example:
SetBounds(Left,Top,Width,Height);

If "Before only", a space is inserted before a comma. All spaces after the comma are re-
moved, as well as ensuring that there is only one space before the comma, e.g.:
SetBounds(Left ,Top ,Width ,Height);

If "After only", a space is inserted after a comma. All spaces before the comma are re-
moved, as well as ensuring that there is only one space after the comma, e.g.:
SetBounds(Left, Top, Width, Height);

If "Before and after", a space is inserted both before and after a comma. Any multiple
spaces will be removed, for example:
SetBounds(Left , Top , Width , Height);

If "Preserve spacing", a space is inserted before and/or after a comma if a number of


spaces already exists. Otherwise, no spaces are inserted, for example:

124
SetBounds(Left , Top,Width ,Height);

becomes:
SetBounds(Left , Top,Width ,Height);

The default setting is "After only", which is also the recommended setting.

2.1.4 Set spacing around semicolons


Defines spaces around a semicolon ";". We use semicolons primarily to end or separate
statements, but also to separate several types of parameters in a procedure or function.
If "None", no spaces should be inserted. All spaces before and after a semicolon will be re-
moved, for example:
function Encode(A: Byte;B: Word;C: ShortInt): Integer;

If "Before only", a space must be inserted after a semicolon. Any spaces before the semico-
lon and all spaces after the semicolon will be removed, for example:
function Encode(A: Byte ;B: Word ;C: ShortInt): Integer ;

If "After only", a space is inserted after a semicolon. It will also remove all spaces before
the semicolon and any excess spaces after the semicolon, for example:
function Encode(A: Byte; B: Word; C: ShortInt): Integer;

If "Before and after", a space must be inserted before and after a semicolon. Any addi-
tional spaces will be removed, for example:
function Encode(A: Byte ; B: Word ; C: ShortInt): Integer ;

If "Preserve spacing", a space is inserted before and/or after a semicolon if a number of


spaces already exist. Otherwise, no spaces are inserted, for example:
function Encode(A: Byte ;B: Word; C: ShortInt): Integer ;

becomes:
function Encode(A: Byte ;B: Word; C: ShortInt): Integer ;

The default setting is "After only" and is also the recommended setting.

2.1.5 Spaces before parentheses in functions


Defines spaces before parentheses "( )" for functions and procedures:
If "Yes", a space is inserted:

125
procedure ScaleBy (M, D: Integer);
begin
ChangeScale (M, D);
end;
If "No", no space is inserted:
procedure ScaleBy(M, D: Integer);
begin
ChangeScale(M, D);
end;
If "Preserve spacing", is inserted on spaces if a number of spaces already exist, e.g. In the
following code:
procedure ScaleBy (M, D: Integer); begin ChangeScale( M, D ); end;

becomes:
procedure ScaleBy (M, D: Integer);
begin
ChangeScale(M, D);
end;
Note: This setting only applies to main-level functions. For example, this option only ap-
plies to the first "F" function in the following statement:
F(F(I), 1);

which after formatting becomes:


F (F(I), 1);

The default setting is "No" and is also the recommended setting.

2.2 Set spacing for comments

2.2.1 Set spacing for // comments


Defines white space around the "//" token for single-line comments. The semicolon is
omitted from the examples below to emphasize the effect of the settings, without the rules
for spaces around semicolons coming into play. Namely, spacing will change according to
semicolon spacing settings and other settings, e.g., when a comment is written immedi-
ately after a reserved word. See also the section of conflict with spaces.
If "Preserve spacing", the following approach is implemented:

• A space is inserted between text and the "//" token if there is space before the "//".
• A space is inserted after the "//" token if spaces exist here.

126
• No space is inserted before or after the "//" token if there is no space beforehand.
• If there is no code before a single-line comment, then the indentation is defined by
the "Indent comments" option.

For example:
Exit //This is just to make code more readable.

becomes:
Exit //This is just to make code more readable.

If "None", no spaces should be inserted. Any spaces after the "//" token are removed and
the token is aligned to a current indentation, for example:
Exit//This is just to make code more readable.

If "Before only", a space is inserted before a "//" token. Any spaces after the "//" token are
removed and the token is aligned to a current indentation, for example:
Exit //This is just to make code more readable.

If "After only", a space is inserted after a "//" token. Any additional spaces after the token
will be removed and the token will be aligned to a current indentation, e.g.:
Exit// This is just to make code more readable.

If "Before and after", a space must be inserted both before and after a "//" token. Any ad-
ditional spaces after the token will be removed and the token will be aligned to a current
indentation, e.g.:
Exit // This is just to make code more readable.

Note: Any spaces used in the rest of a comment are preserved. And if there is no code be-
fore the comment, the comment will by default be adjusted to a current indentation re-
gardless of the space before a comment of 2 slashes.
The default setting is "Before and after" and is also the recommended setting.

2.2.2 Set spacing for { and (* comments


Defines whitespace around opening curly braces "{" or "(*" and closing curly braces "}" or
"*)" in block comments.
If "Preserve spacing", the following approach is implemented:

• A space is inserted before an opening parenthesis "{" or "(*") if there is code before
"{" or "(*" on the line, and otherwise any spaces are preserved exactly as they are
before "{" or "(*) .

127
• A space is inserted after "{", "(*", "}", or "*)" and before "}" or "*)" if spaces already
exist in the code.
• No spaces are inserted if no spaces already exist immediately before or after "{",
"(*", "}", or "*)" in a code.
• If no code precedes a "{" or "(*" comment, then the indentation of the comment is
defined by the "Indent comments" option. Continuation lines (when a comment is
broken and continues on multiple lines) are indented according to option for "In-
dent comments" option.

For example:
if True {False omitted } then

becomes:
if True {False omitted } then

If "None", no spaces should be inserted. Any spaces are removed after an opening curly
brace "{" and before an ending curly brace "}" and the comment is aligned to the current
indentation, for example:
if True{False omitted} then

If "Inner only", only spaces are inserted inside parentheses. A space is inserted just after
each opening parenthesis "{" or "(*" and before each closing parenthesis "}" or "*)", for ex-
ample:
if True{ False omitted } then

If "Outer only", only spaces outside parentheses are inserted. A space is inserted before
each opening bracket "{" or "(*" and after each closing bracket "}" or "*), for example:
if True {False omitted} then

If "Inner and outer", spaces are inserted both inside and outside the parentheses. A space
is inserted before and after each opening parenthesis "{" or "(*" and each closing paren-
thesis "}" or "*)", for example:
if True { False omitted } then

Bemærk: Alle mellemrum, der bruges i kommentarer, bevares.


Defaultindstillingen er "Inner and outer" og er også den anbefalede indstilling.

2.3 Set spacing for operators


Operatorer dækker over alle typer af operatorer, som er aritmetiske, relationelle og logiske
operatorer.

128
2.3.1 Set spacing around assignment operators
Defines spaces around assignment operator ":=":
If "None", no spaces should be inserted:
A:=B;

If "Before only", a space is inserted before an assignment operator:


A :=B;

If "After only", a space is inserted after an assignment operator:


A:= B;

If "Before and after", a space must be inserted both before and after an assignment opera-
tor:
A := B;

If "Preserve spacing", a space is inserted before and/or after an assignment operator if a


number of spaces already exist in the code. Otherwise, no spaces are inserted, e.g., the fol-
lowing code:
A :=B;

becomes:
A :=B;

The default setting is "Before and after" and is also the recommended setting.

2.3.2 Set spacing around binary operators


Defines spaces around binary mathematical operators such as "<", ">", "=", "<>", "<=",
">=", "+", "-", "/", "*", "..", "or", "and", "xor", "div":
If "None", no spaces should be inserted:
A := A+C*D;

If "Before only", a space is inserted before each binary mathematical operator:


A :=B +C *D;

If "After only", a space is inserted after each binary mathematical operator:


A := B+ C* D;

If "Before and after", a space must be inserted both before and after each binary mathe-
matical operator:

129
A := B + C * D;

The default setting is "Before and after" and is also the recommended setting.

2.3.3 Set spacing around unary prefix operators


Defines spaces around unary prefix operators "+", "-", "not":
If "None", no spaces should be inserted:
A := B+-C;

If "Before only", a space is inserted before a unary prefix operator:


A := B+ -C;

If "After only", a space is inserted after a unary prefix operator:


A := B+- C;

If "Before and after", a space must be inserted both before and after a unary prefix opera-
tor:
A := B+ - C;

If "Preserve spacing", a space is inserted before/after a unary prefix operator if a number


of spaces already exist in the code. Otherwise, no spaces are inserted, e.g. the following
code:
A :=B+- C;

becomes:
A :=B+- C;

The default setting is "None", which is the recommended setting, but it also affects the
unary word "not", e.g.:
if not True then

would pass, but the space is removed if parentheses are used, e.g.:
if not(True) then

2.4 Set spacing for parentheses and brackets


The recommended use of parentheses follows a common practice of round and square
brackets in mathematics, which will of course also affect a compiler's evaluation of en-
closed statements.

130
2.4.1 Set spacing for parentheses
If "True", a space is inserted after each opening parenthesis "(" and before each closing
parenthesis ")", e.g.:
procedure FocusControl( Control: TWinControl );

If "False", no spaces must be inserted after a starting parenthesis ")" and before a closing
parenthesis "")", e.g.:
procedure FocusControl(Control: TWinControl);

The default setting is "False" and is also the recommended setting.

2.4.2 Set spacing for square brackets


If "True", a space must be inserted after each opening square bracket "[" and before each
closing square bracket "]":
BorderStyles: array [ TBorderStyle ] of DWORD;

If "False", no spaces should be inserted:


BorderStyles: array [TBorderStyle] of DWORD;

The default setting is "False" and is also the recommended setting.


Note: Array declarations are traditionally written without a space between the array
and before an opening angle bracket, but Code Formatter adds a space.

2.4.3 Set spacing inside angle brackets in generics


Defines internal spaces within the angle brackets "<" and ">" used in generics to specify
lists with a type argument.
If "True", a space is inserted after each left "<" bracket and before each right ">" bracket,
e.g.:
TArray< T > = array of T;

If "False", no spaces should be inserted:


TArray<T> = array of T;

The default value is "False", which is the recommended setting.

2.5 Spacing conflicts


We rarely think about conflicting rules for spaces, as we often unconsciously prioritize
which rule, we think about while writing code. But Code Formatter must necessarily have
rules for rules that conflict with each other, e.g., in aforementioned examples with Exit
and comment with double slashes, e.g.:

131
Exit; // This is just to make code more readable.

The space between semicolons ";" and the "//" token is governed by both rules for spacing
around semicolons and rules for spacing around 2 slashes. The conflict arises if one of the
rules would dictate a space and the other rule dictates that there should not be a space.

2.5.1 Resolve space conflicts as


Defines how Code Formatter handles spaces in places controlled by multiple conflicting
options. For example, one option may require that a space be inserted somewhere, while
another option may define that no space be inserted in the exact same place. This option
controls such conflicting rules:
If "No space", no space should be inserted, e.g., if the above example dictates "None" in a
rule or both rules for semicolons and comments with 2 slashes, then there will be no
spaces. If both rules dictate a space, there will be no conflict and a space will then be in-
serted.
If "Space", a space is inserted, e.g., if the above example dictates a space in a rule or both
rules for semicolons and comments with 2 slashes, then a space will be inserted. If both
rules say "None", there will be no conflict and spaces will be removed.
If "Preserve spacing", a space must be inserted if there is already a number of spaces in a
given place in the code. Otherwise, no spaces should be inserted. This option will not
change existing spaces except that excess spaces would be removed.
The default setting is "Space", which is also the recommended setting.

Line Breaks
There are a few different types of line breaks, and it's not so much the difference in types
like End-Of-Line or CRLF, but rather types of how lines are broken over multiple lines, in
so-called continuation lines. Usually, each statement has a line break after a semicolon,
and other types of code constructions, e.g., if-then-else or case statements are constructed
over several lines, and statements that do not fit on a single line must continue on a new
line, hence the continuation line.
We will also find options to split a list, e.g., for a list of units in a uses clause, or a list of ar-
guments or parameters, etc. Each element can be listed on its own line, or all elements
can be listed on a single line, and perhaps only broken in a continuation line after a right
margin.

3.1 General

3.1.1 Keep user line breaks


If "True", preserve line breaks in the source code, e.g.:

132
A := (B+C)*
(D-E);
becomes:
A := (B + C) *
(D - E);
The rules for indentation of broken lines and spaces are applied, but line breaks are pre-
served, although there is plenty of room to format the entire statement to one line.
If "False", existing line breaks are ignored:
A := (B + C) *
(D - E);
becomes:
A := (B + C) * (D - E);

The default setting is "False" and should be the recommended setting.

3.1.2 Line break characters


Defines the characters that will be inserted as line breaks:
If "Default value of the system", the default values for line breaks in a system must be
used (e.g., \r\n for Windows).
If "Windows", \r\n (or 0D and 0A) must be used as a line break regardless of system.

If "Unix", \n is used.
If "Mac", \r is used.
Note: This option only works for stand-alone formatter (Formatter.exe). RAD Studio IDE
(bds.exe) always uses "Default value of the system" (\r\n for Windows).
The default setting is "Default value of the system" and should be the recommended set-
ting.

3.1.3 Right margin


Defines the right margin to break longer lines of code, i.e., default is 80 characters before
a line break into additional continuation lines.
Code Formatter does not respect the right margin setting for the editor, which can be
found in User Interface > Editor > Display, which is also set to 80 characters by default,
and Code Completion reads the setting for the editor. This means that if there is a dis-
crepancy between the two settings, e.g., 80 characters for the editor and 160 characters
for the Code Formatter, code added by Code Completion with broken lines and

133
continuation lines will be reformatted. A change in one of the settings will also be re-
flected by formatting according to the other setting.
The default setting is inherited from the old monitors with only 80 characters, and mod-
ern high-resolution graphic displays can easily display 120 characters, or 160 characters
with a large font size as acceptable settings. A setting of 120 characters will eliminate the
need for line breaks for most methods that cannot be written on a single line. Changing
these settings should be standardized within a project and teams, as it can also affect doc-
umentation and conflicting settings across team members, introducing unnecessary noise
in version control and code reviews.

3.1.4 Trim source


Source code trimming controls the removal of white spaces (spaces, tabs, and line breaks)
from the beginning to the end of the file.
If "True", all white spaces from the beginning to the end of the file are removed.

• Stand-alone formatter (Formatter.exe) always adds a blank line at the end of the
file.
• RAD Studio IDE (bds.exe) adds a blank line at the end of a saved file.

If "False", white spaces in the file must not be removed.


Note: The integrated Code Formatter always removes white space at the end of a file.
The default setting is "True".

3.2 Insert line breaks


The subsequent settings change typical code constructions, e.g., how if-then-else con-
structs break, etc. Inserting these line breaks does not affect rules for line breaks but can
still completely change the styling of code constructs.

3.2.1 Line break after label


Defines whether line breaks should be inserted after labels.
If "Yes", line breaks are inserted, e.g.:
goto Done;
Done:
Exit;
If "No", no line breaks must be inserted, e.g.:
goto Done;
Done: Exit;
If "As is", preserves the line break as written in the code, e.g., nothing will be changed af-
ter labels.

134
The default setting is "Yes", which is also the recommended setting.
Note: This setting does not affect styling of labels used in inline assembler code.

3.2.2 Line break inside "Else If"


Defines whether line breaks should be inserted between "else" and "if" in nested "if" state-
ments:
If "True", line breaks are inserted:
if Visible then
WindowState := wsMaximized
else
if Enabled then
WindowState := wsNormal;
If "False", no line breaks should be inserted:
if Visible then
WindowState := wsMaximized
else if Enabled then
WindowState := wsNormal;
The default setting is "False".
Both stylizations of "else if" statements are fully acceptable by the new style guide, alt-
hough the default ("False") will result in fewer indentation levels, and the first ("True")
will depict the real indentation levels of all nested "if" statements.

3.2.3 Line breaks after semicolons


Defines whether to insert a line break after each semicolon:
If "True", a line break is inserted after each semicolon ";" before a new statement:
A := B + C;
D := A - C;
Hvis "False", skal der ikke indsættes oversete linjeskift efter et semikolon, f.eks.:
A := B + C; D := A - C;

Note: Line breaks are not added after internal semicolons in declarations, definitions, etc.,
e.g.:
procedure EndDrag(Target: TObject; X, Y: Integer); override;

Note: Line breaks are always added before/after the most significant statement: definition
of classes and declarations, definition of methods and declarations, loops, control state-
ments and others.
The default setting is "True", which is also the recommended setting.
135
3.2.4 Line breaks after Uses keywords
Defines whether line breaks should be inserted after the keywords uses, label, export, re-
quires and contains:
If "Yes", insert line breaks after each of the mentioned keywords:
uses
Winapi.Windows, Winapi.Messages, System.SysUtils;
If "No", no line breaks must be inserted after any of the mentioned keywords:
uses Winapi.Windows, Winapi.Messages, System.SysUtils;

If "As is", line breaks are preserved as written in the source code.
The default setting is "As is", which is not the recommended setting. According to the new
style guide, the names of units must start on a line following the keyword "uses" and be
indented with 2 spaces. The recommended setting should be "Yes".

3.2.5 Line breaks before Then


Defines the placement of the keyword "then" in "if" statements:
If "True", each "then" keyword must be placed on a new line:
if Visible
then
WindowState := wsMaximized;
If "False", the keyword "then" is placed on the same line as the "if" statement:
if Visible then
WindowState := wsMaximized;
The default setting is "False", which is also the recommended setting.

3.2.6 Line breaks in Anonymous Function assignments


Defines whether to insert a newline after an Anonymous Function assignment operator:
If "True", a line break is inserted:
IntToStrFunc :=
function(I: Integer): string
begin
Result := IntToStr(I);
end;
If "False", no line break should be inserted:

136
IntToStrFunc := function(I: Integer): string
begin
Result := IntToStr(I);
end;
The default setting is "False", and although it is not explicitly described in the style guide,
this is the common stylization in the documentation, and should therefore be the recom-
mended setting.

3.2.7 Line breaks in Anonymous Function usage


Defines whether to insert a line break when using Anonymous Function:
If "True", a line break is inserted:
TThread.Queue(nil,
procedure
begin
FList.Clear;
end);
If "False", no line break should be inserted:
TThread.Queue(nil, procedure
begin
FList.Clear;
end);
The default setting is "True", which is the recommended setting, although the documen-
tation can be a bit confusing, as the examples tend to illustrate functions or procedures on
the same line as statements. This is clearly marked as wrong in the new style guide.
The intent of this stylization is to have a complete visual appearance of an entire block of
code, aligned with the same indentation.

3.2.8 Line breaks in array initializations


Controls line breaks in initialization of arrays. This option does not affect declarations of
arrays in a const section, and therefore only in a var section:

If "Yes", line breaks are inserted:


var
Styles: array [TScrollBarStyle] of Integer = (
FSB_REGULAR_MODE,
FSB_ENCARTA_MODE,
FSB_FLAT_MODE
);
If "No", no line breaks must be inserted:

137
var
Styles: array [TScrollBarStyle] of Integer = (FSB_REGULAR_MODE,
FSB_ENCARTA_MODE, FSB_FLAT_MODE);
If "As is", line breaks are preserved as written in the source code:
var
Styles: array [TScrollBarStyle] of Integer = (FSB_REGULAR_MODE,
FSB_ENCARTA_MODE,
FSB_FLAT_MODE
);
If "Only first dimension", only line breaks are inserted for elements of the first dimension
(in multidimensional arrays):
ArrayStates: array [0 .. 1, 0 .. 1] of string (
(‘AL’, ‘ALABAMA’),
(‘AK’, ‘ALASKA’)
);
The default setting is "Yes".
Note: The last option, "Only first dimension", had no effect in any of the array initializa-
tions that were set up for testing.
Also note: The space around ".." is a bug in Code Formatter that misinterprets set con-
structor (double periods) as a binary operator. Unfortunately, spaces around the double
periods can only be removed by setting "Set spacing around binary operators" to "None",
which will of course affect the overall stylization considerably through such a setting.

3.2.9 Line breaks in Inheritance lists


Defines placement of base classes and interfaces in a list of inheritances:
If "Yes, first name on the same line":

• place the first name of the base class on the same line as the name of the declared
class
• place each name of the other base classes on a new line,
• and indent these names against the statement:

type
TInterfaceList = class(TInterfacedObject,
IInterfaceList,
IInterfaceListEx)
end;
If "Yes, first name on the next line":

• place the first name of the base class on the next line after the declared class

138
• and place each name of the other base classes on a new line:

type
TInterfaceList = class(
TInterfacedObject,
IInterfaceList,
IInterfaceListEx)
end;
If "No", the names of all base classes are placed on the same line as the declared class,
e.g.:
type
TInterfaceList = class(TInterfacedObject, IInterfaceList, IInterfaceListEx)
end;

If "As is", the location of base classes is preserved on lines as written in the source code,
e.g.:
type
TInterfaceList = class(TInterfacedObject,
IInterfaceList, IInterfaceListEx)
end;
The default setting is "No", which is the common stylization and should be the recom-
mended setting.

3.2.10 Line breaks in Labels, Export, Requires, Contains clauses


Defines whether newlines should be inserted before each element in label, export,
requires, contains clauses:

If "Yes", line breaks are inserted. Any declarations separated by a comma will be broken
into separate lines, for example:
label
Done,
Loop;

contains
System.Classes in "System.Classes.pas",
Vcl.Controls in "Vcl.Controls.pas";
If "No", no line breaks must be inserted. Any line breaks will be removed and all declara-
tions will be formatted on the same line and follow the rules for line breaks if the declara-
tion exceeds one line, for example:

139
label Done, Loop;

contains System.Classes in "System.Classes.pas",


Vcl.Controls in "Vcl.Controls.pas";

exports encmsg EncodeMIDIMsg, decmsg DecodeMIDIMsg;


If "As is", line breaks are preserved as written in the source code.
See also "Line breaks after Uses keywords" and "Line breaks in Uses clauses".
The default setting is "As is", but common practice for all the keywords mentioned is a
separate line for each statement, so "Yes" should be the recommended setting.

3.2.11 Line breaks in Property declarations


Defines whether to insert a line break before each keyword such as read, write,
stored, default in declarations of properties:

If "True", line breaks are inserted. Each of the keywords is separated in each line, includ-
ing the keyword default, for example:
property Lines: TStrings
read GetLines
write SetLines
stored IsLinesStored;
If "False", no line breaks should be inserted:
property Lines: TStrings read GetLines write SetLines
stored IsLinesStored;
The default setting is "False" and is also the recommended setting.
Note: The keyword default will lose its stylization, i.e., bold font, if separated on its
own line but will still be valid and compilable.

3.2.12 Line breaks in Uses clauses


Defines whether to insert a line break before each element in uses clauses:
If "Yes", each element of uses clauses is placed on a new line:
uses System.SysUtils,
Vcl.Controls;
If "No", place all elements in uses clauses on the same line, and follow the rules for broken
lines if elements exceed the line, e.g.:
uses System.SysUtils, Vcl.Controls;

If "As is", line breaks are preserved as written in the source code.

140
See also "Line breaks after Uses keywords".
The default setting is "As is", and that would be the recommended setting, as the setting
for "Line breaks after Uses keywords" should be set to "Yes" as recommended.

3.2.13 Line breaks in Var and Const sections


Defines whether to insert a newline before each element in var and const sections:

If "yes", each element in var or const sections is placed on a new line, e.g.:

const
X = 10;
Y = 20;
var
A: Integer;
B, C: Integer;
If "No", all elements in var or const sections are placed on the same line, e.g.:

const X = 10; Y = 20;


var A: Integer; B, C: Integer;
If "As is", line breaks are preserved as written in the source code.
The default setting is "Yes" and should be the recommended setting.

3.2.14 Remove line breaks inside "End Else Begin"


Defines whether line breaks should be removed inside an end else begin construct:

If "True", remove all line breaks in an end else begin construct, e.g.:

if Visible then
begin
WindowState := wsMaximized;
end else begin
WindowState := wsNormal;
end;
If "False", use line breaks in an end else begin construct defined by other options,
for example:
if Visible then
begin
WindowState := wsMaximized;
end
else
begin
WindowState := wsNormal;
end;

141
Note: If "True", the begin keyword after a then keyword should be formatted according
to a "No" setting in "Line break after Begin".
The default setting is "False" and is also the recommended setting.

3.2.15 Remove line breaks inside "End Else If"


Defines whether to remove line breaks in an end else if construction:

If "True", all line breaks in an end else if construction are removed, e.g.:

if Visible then
begin
WindowState := wsMaximized;
end else if Enabled then
WindowState := wsNormal;
If "False", use newlines in an end else if construction, as defined by other options,
e.g.:
if Visible then
begin
WindowState := wsMaximized;
end
else if Enabled then
WindowState := wsNormal;
The default setting is "False" and is also the recommended setting.

3.3 Insert line breaks for Begin and Single instructions


Despite the standard stylization, it is possible to find examples of stylization of code
blocks enclosed by begin and end, and statements on one line.

3.3.1 Line breaks after Begin


Defines whether to insert a newline after a begin keyword:

If "Yes", insert a line break after begin, e.g.:

begin
Color := clBtnFace;
WindowState := wsMaximized;
end;
If "No", a line break must not be inserted after begin, e.g.:

begin Enabled := True;


WindowState := wsMaximized;
end;

142
If "As is", line breaks are preserved as written in source code.
Note: The above examples use a pair of begin/end without a control statement, as this
option handles situations that are not controlled by the settings for "Line breaks after
Begin in method definitions" and "Line breaks after begin in control statements". See the
next two options.
The default setting is "Yes" and it is also the recommended setting.

3.3.2 Line breaks after Begin in control statements


Defines whether a line break should be inserted after begin in conditional statements if
else or case and in loop statements while do, for do, and with do:

If "Yes", a line break is inserted after begin, e.g.:

if Visible then
begin
Color := clBtnFace;
WindowState := wsMaximized;
end;
If "No", no line breaks must be inserted after begin, e.g.:

if Visible then
begin Color := clBtnFace;
WindowState := wsMaximized;
end;
If "As is", line breaks are preserved as written in the source code.
The default setting is "Yes" and it is also the recommended setting.

3.3.3 Line breaks after Begin in method definitions


Defines whether to insert a line break after the keyword begin in the definition of a
method:
If "Yes", a line break is inserted after begin, e.g.:

procedure TMainForm.FormShow(Sender: TObject);


begin
Color := clBtnFace;
WindowState := wsMaximized;
end;
If "No", no line breaks must be inserted after begin, e.g.:

143
procedure TMainForm.FormShow(Sender: TObject);
begin Color := clBtnFace;
WindowState := wsMaximized;
end;
If "As is", line breaks are preserved as written in the source code.
The default setting is "Yes" and it is also the recommended setting.

3.3.4 Line breaks before Begin in control statements


Defines whether a line break should be inserted before begin in conditional statements
if else or case and in loop statements while do, for do, and with do:

If "Yes", a line break is inserted, e.g.:


while Visible do
begin
Visible := False;
end;
If "No", no line breaks must be inserted, e.g.:
while Visible do begin
Visible := False;
end;
If "As is", line breaks are preserved as written in the source code.
The default setting is "Yes" and it is also the recommended setting.

3.3.5 Line breaks before single instructions in control statements


Defines whether to insert line breaks before single statements in conditional statements
if/else, case and in loop statements while/do, for/do, with/do, and re-
peat/until:

If "Yes", line breaks are inserted:


if Enabled then
Visible := True
else
Visible := False;

with TStringList.Create do
Free;

for I := 0 to 1 do
Tag := Tag + I;
If "No", no line breaks must be inserted:

144
if Enabled then Visible := True
else Visible := False;

with TStringList.Create do Free;

for I := 0 to 1 do Tag := Tag + I;


If "As is", line breaks are preserved as written in the source code.
See also "Line breaks before Begin in control statements".
The default setting is "Yes" and it is also the recommended setting.

3.3.6 Line breaks before single instructions in try-except blocks


Defines whether newlines should be inserted before single statements in try/except
and try/finally blocks:

If "Yes", line breaks are inserted:


try
I := StrToInt('A');
except
Writeln('Intentional exception.');
end;
If "No", no line breaks must be inserted:
try I := StrToInt('A');
except Writeln('Intentional exception.');
end;
If "As is", line breaks are preserved as written in the source code.
The default setting is "Yes" and it is also the recommended setting.

3.4 Line breaks in functions


Line breaks are atypical in stylization of the return type of functions, and for both argu-
ments and parameters in function declarations and calls. However, a few formal style
guides recommend a strict separation of the different elements of a function. The original
and new style guides follow a rule of keeping related declarations and statements on the
same line if possible and apply line breaks where necessary.

3.4.1 New line for a function return type


Defines placement of the return type in a declaration and definition of a function:
If "Yes", the return type is placed on a new line, e.g.:
function CompareStr(const S1, S2: string)
: Integer; overload;

145
If "No", the return type must be placed on the same line as the name of the function:
function CompareStr(const S1, S2: string): Integer; overload;

If "As is", the location of return types is preserved as written in the source code.
Note: This setting only has an effect if the function has parameters.
The default setting is "No" and is also the recommended setting.

3.4.2 One parameter per line in function calls


Defines placement of arguments in calls to functions or procedures:
If "Yes", each argument (if more than one) must be placed on a new line:
Result := CompareStr(
'Normann',
'Norm4nn');
If "No", all arguments must be placed on the same line as the function name:
Result := CompareStr('Normann', 'Norm4nn');

If "As is", the positioning of lines with the arguments is preserved as written in the source
code.
Note: This option only works if the function/procedure is called as a statement, for exam-
ple:
CompareStr(...);
Result := CompareStr(...);
The default setting is "No" and this is also the recommended setting.

3.4.3 One parameter per line in function definition


Defines placement of parameters in declarations and definitions of functions and proce-
dures:
If "Yes", each parameter (if more than one) must be placed on a new line:
function AnsiStrLComp(
S1, S2: PWideChar;
MaxLen: Cardinal): Integer;

If "No", all parameters must be placed on the same line as the function name:
function AnsiStrLComp(S1, S2: PWideChar; MaxLen: Cardinal): Integer;

If "As is", the location of parameters is preserved as written in the source code.
Note: This option does not work for multiple parameters that are simply declared with
one type separated by a comma, for example:

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

The default setting is "No" and is also the recommended setting.

3.5 Number of empty lines


Some types of blank lines are also known as vertical white spaces. They are usually used
to separate sections of code, e.g., keywords such as interface, implementation and be-
tween classes and other. However, blank lines can also be used to group related blocks of
code that are affected by these settings if they consist of more blank lines than specified.

3.5.1 Max number of adjacent empty lines


Defines the maximum number of contiguous and user-defined blank lines in the code:
If "0", formatted code will only contain blank lines added by the Code Formatter, e.g.:
Color := clBtnFace;

WindowState := wsMaximized;
becomes:
Color := clBtnFace;
WindowState := wsMaximized;
If "1", only one custom blank line will be preserved in a formatted code in each group of 2
or more blank lines.
Note: Any contiguous blank lines higher than a specified number greater than 1 will be
trimmed to the specified number of blank lines. Any adjacent blank lines less than the
specified number of blank lines will not be increased to the specified number of blank
lines.
The default setting is "1" and would also be the recommended setting for separating sec-
tions and related blocks of codes.

3.5.2 Number of empty lines around compiler directives


Defines the number of blank lines used as separators on compiler directives.
If "0", only blank lines after a compiler directive will be removed, and not blank lines be-
fore a compiler directive.
If "1", blank lines are added before and after a compiler directive, for example:

147
begin
{$IFDEF DEBUG}
Color := clHighlight;
{$ENDIF}
end;
bliver til
begin

{$IFDEF DEBUG}

Color := clHighlight;

{$ENDIF}

end;
Note: Any number of blank lines higher than a specified number higher than "1" will trim
the blank lines to the specified number of lines, before and after a compiler directive. A
number of blank lines less than the specified number greater than "0" will trim blank lines
to the specified number of lines before and after a compiler directive.
The default setting is "0" and should be the recommended setting.

3.5.3 Number of empty lines around section keywords


Defines the number of blank lines used to separate sections such as interface, im-
plementation, and other keywords that define a section.

If "0", the setting will act as "As is", meaning that any number of blank lines before and
after a section keyword will be trimmed according to the number of adjacent blank lines
settings. Any missing blank lines before and after a keyword for a section will be pre-
served if no other rule supersedes and conflicts are not resolved with a space.
If "1", any missing blank lines around a keyword for a section are added and any excess
lines are removed.
Note: A number higher than "1" will work the same, except for the higher number of
blank lines as specified.
The default setting is "1" and is also the recommended number of blank lines to separate
sections.

3.5.4 Number of empty lines as separator in implementation sect.


Defines the number of blank lines as separator in an implementation section.

148
If "0", the setting will work as an "As is", which means that a number of blank lines before
and after implementations, e.g., a procedure or function, will be trimmed according to the
settings for the number of adjacent blank lines. Any missing blank lines before and after
an implementation will be preserved if no other rule takes its place or conflicts are re-
solved with a space, for example:
const
DefaultIndex: Integer = -1;
procedure Init(var Index: Integer);
begin
Index := DefaultIndex;
end;
If "1", any missing blank lines around an implementation are added and any excess blank
lines are removed, e.g.:
const
DefaultIndex: Integer = -1;

procedure Init(var Index: Integer);


begin
Index := DefaultIndex;
end;
Note: A number higher than "1" will work the same, except with a higher number of
blank lines as specified.
The default setting is "1" and is also the recommended number of blank lines to separate
multiple implementations:

3.5.5 Number of empty lines as separator in interface section


Defines the number of blank lines used as a separator in an interface section. This setting
will affect the spacing between declarations of classes and interface with constructs, e.g.
up to the keyword end, and not declarations on a single line, for example:

149
TScrollingWinControl = class;
TCustomForm = class;
TScrollBarStyle = (ssRegular, ssFlat, ssHotTrack);

IOleForm = interface
procedure OnDestroy;
procedure OnResize;
end;

TMainForm = class(TForm)
private
public
end;
If "0", the setting will act as an "As is", meaning that a number of blank lines before and
after a declaration of class or interface will be trimmed according to the settings for the
number of adjacent blank lines. Any missing blank lines before and after a keyword for a
section will be preserved if no other rule takes its place or conflicts are resolved as a space.
If "1", any missing blank lines are added between the statements and any excess blank
lines are removed.
Note: A number higher than "1" will work the same, except with a number of blank lines
as specified.
The default setting is "1" and is also the recommended number of blank lines to separate
statements.

3.5.6 Number of empty lines before subsections


Defines the number of blank lines used as separators before const, label and other
subsections. This option does not affect sections nested in procedures or functions, only
in the outer sections of the interface or implementation, for example:

implementation

const
DefaultIndex: Integer = -1;

var
MaxIndex: Integer;
If "0", the setting will work as an "As is", which means that a number of blank lines before
and after subsections will be trimmed according to the settings for the number of contigu-
ous blank lines. Any missing blank lines before and after a subsection will be preserved if
no other rule supersedes or conflicts are resolved as a space.

150
If "1", any missing blank lines between subsections are added and any excess blank lines
are removed.
Note: A number higher than "1" will work the same, except with a number of blank lines
as specified.
The default setting is "1" and is also the recommended number of blank lines to separate
subsections.

3.5.7 Number of empty lines before Type keyword


Defines the number of blank lines used as a separator before the type keyword.

If "0", the setting will act as an "As is", meaning that a number of blank lines before the
keyword type will be trimmed according to the settings for the number of adjacent blank
lines. Any missing blank lines before the keyword will be preserved if no other rule takes
its place or conflicts are resolved as a space.
If "1", a missing blank line is added before the type keyword and any excess blank lines
are removed.
Note: A number higher than "1" will work the same, except with a number of blank lines
as specified.
The default setting is "1" and is the recommended number of blank lines before the key-
word, for example:
uses
System.Classes, Vcl.Controls, Vcl.Forms;

type
TMainForm = class(TForm)
3.5.8 Number of empty lines before visibility modifiers
Defines the number of blank lines used as a separator before visibility modifiers.
If "0", the setting will act as an "As is", which means that a number of blank lines before
an access specifier will be trimmed according to the settings for the number of adjacent
blank lines. Any excess blank lines before an access specifier will be preserved if no other
rule supersedes or a conflict is resolved with a space.
If "1", a missing blank line is added before an access specifier if it is not the first specifier,
and any excess blank lines are removed, e.g.:

151
private
FValue: Integer;

protected
FHandle: NativeUInt;

public
property Value: Integer read FValue;
end;
Note: A number higher than "1" will work the same, except with a higher number of
blank lines as specified.
The default setting is "0" and is also the recommended number of blank lines before and
after an access specifier, for example:
private
FValue: Integer;
protected
FHandle: NativeUInt;
public
property Value: Integer read FValue;
end;

Capitalization
Capitalization or stylization of letters is probably the most visual and characteristic aspect
of a programming language.

4.1 General
Although an important aspect of styling code, this group of settings only consists of 4 op-
tions. The areas of code most affected by Code Formatter are probably identifiers, but
there is not a separate option for these as they are covered by "Capitalization of other
words".
Code Formatter is thus missing a very important rule for stylizing letters, as it has a big
problem respecting identifiers that have already been declared. It will e.g., just format
midiInOpen to "As first occurrence", and not as declared in the API implementation of
Winapi.MMSystem. If a first instance is defective, then all subsequent instances will be
defective.
Stylization of identifiers from another framework used in a project should be respected.

4.1.1 Capitalization of compiler directives


Defines styling of compiler directives: {$IFDEF}, {$WARNINGS *}, {$STACKCHECKS
*}, and others:

152
If "First character in Uppercase", the first character in names of compilation directives
should be capitalized, and stylization of all other characters is kept as is, for example:
{$ifdef debug}
{$ifDef DEBUG}
becomes:
{$Ifdef debug}
{$IfDef DEBUG}
If "As first occurrence", stylization of a compiler directive is written as in the first occur-
rence of the same directive in the file, e.g.:
{$Ifdef debug}
{$IfDef DEBUG}
becomes:
{$Ifdef debug}
{$Ifdef DEBUG}
If "lowercase", all compiler directives are converted to lowercase, e.g.:
{$Ifdef debug}
{$IfDef DEBUG}
becomes:
{$ifdef debug}
{$ifdef DEBUG}
If "UPPERCASE", all compiler directives are converted to upper case, for example:
{$Ifdef debug}
{$IfDef DEBUG}
becomes:
{$IFDEF debug}
{$IFDEF DEBUG}
If "As is", stylization of all letters is preserved.
Note: This setting does not affect the actual condition in the directive, e.g., as in the exam-
ples "DEBUG", which should be as important as the compiler directive, here "IFDEF".
The recommended styling of the elements is UPPERCASE, and it is only possible to for-
mat the directives (partially) using the Code Formatter. Code Completion and other fea-
tures will not try to make any difference.

153
4.1.2 Capitalization of numbers
Defines styling used in hexadecimal ($Fa) and floating point (1.23e-8) numbers, includ-
ing characters in prefixes and suffixes.
If "First character in Uppercase", the first character in the number must be capitalized
and the stylization of the other characters must be preserved. However, this setting does
not work.
If "As first occurrence", stylization for any number must be written as at the first occur-
rence of the number in the file. However, this setting does not work.
If "lowercase", all numbers are converted to lowercase letters, e.g.:
I := $Fa;
D := 1.23E-8;
becomes:
I := $fa;
D := 1.23e-8;
If "UPPERCASE", all numbers are converted to capital letters, e.g.:
I := $Fa;
D := 1.23e-8;
becomes:
I := $FA;
D := 1.23E-8;
The default setting is "UPPER CASE" and is also the recommended setting.

4.1.3 Capitalization of other words


Defines the stylization of words that do not belong to any of the following groups:

• reserved words – "if", "then", "array", and others,


• directives – "abstract", "automated", and others,
• compiler directives – {$IFDEF}, {$WARNINGS *}, and others,
• number – hexadecimal or floating-point numbers containing letters.

If "First Character in Uppercase", the first letter of each word must be capitalized and styl-
ization preserved for all other letters, e.g.:
setPosition
getLeftPosition

becomes:

154
SetPosition
GetLeftPosition

If "As first occurrence", the stylization of all letters in a word must be written as in the first
occurrence of the word in the file. This is the default setting, which highlights the mean-
ing in a discipline by styling especially the first occurrence of an identifier, including the
first reference to identifiers declared elsewhere than in the current file.
If "lowercase", all words are converted to lowercase, e.g.:
SetPosition
GetLeftPosition

becomes:
setposition
getleftposition

If "UPPERCASE", all words are converted to upper case, for example:


SetPosition
GetLeftPosition

becomes:
SETPOSITION
GETLEFTPOSITION

If "As is", the stylization must be preserved for all letters.


Note: Identifiers in "program" and "unit" statements (thus the name of the file) are always
stylized as with an "As is" option.
The default setting is "As first occurrence", and should be the recommended setting with a
caveat, as no other setting would be satisfactory for how identifiers should be styled ac-
cording to the style guide.

4.1.4 Capitalization of reserved words and directives


Defines styling of reserved words (if, then, var, and others) and directives (private,
virtual, and others).

If "First Character in Uppercase", the first letter of each reserved word and directive must
be capitalized and stylization for all other letters preserved, e.g.:
threadVar RefCount: Integer;
procedure SetText(const AText: string); VIRTUAL;
resourcestring S = ’Capitalization’;

155
becomes:
ThreadVar RefCount: Integer;
Procedure SetText(Const AText: String); VIRTUAL;
Resourcestring S = ’Capitalization’;
If "As occurrence", all letters in a reserved word or directive must be styled as in the first
occurrence of the same word in the file, for example:
Procedure SetCaption(CONST AText: String); virtual;
procedure SetText(const AText: string); VIRTUAL;
becomes:
Procedure SetCaption(CONST AText: String); virtual;
Procedure SetText(CONST AText: String); virtual;
If "lowercase", all reserved words and directives are written in lower case, e.g.:
threadVar RefCount: Integer;
procedure SetText(const AText: string); VIRTUAL;
resourcestring S = ‘Capitalization’;
becomes:
threadvar RefCount: Integer;
procedure SetText(const AText: string); virtual;
resourcestring S = ‘Capitalization’;
If "UPPERCASE", all reserved words and directives are capitalized, e.g.:
Procedure SetCaption(CONST AText: String); virtual;
procedure SetText(const AText: string); VIRTUAL;
becomes:
PROCEDURE SetCaption(CONST AText: STRING); VIRTUAL;
PROCEDURE SetText(CONST AText: STRING); VIRTUAL;
If "As is", the stylization of all letters is preserved.
The default setting is "As is", but the recommended setting is "lowercase" as described in
the style guide.

Align
Despite the recommendations in the style guide not to use vertical alignment in declara-
tions, the feature can be a good tool for creating or maintaining a larger list of declara-
tions.

156
5.1 Alignment cases
Most cases with alignment happen on the "=" operator, assignments with ":=" and col-
umns with ":". It is also possible to align properties for elements and comments vertically.
All settings are either "True" or "False", and "False" is the default and is also the recom-
mended setting for alignment.

5.1.1 Align "=" in constants


If set to "True", must be adjusted according to the assignment operator "=" in the initiali-
zation of constants, e.g.:
const
Minimum = 0;
Max = 127;
The default setting is "False", which is also the recommended setting.

5.1.2 Align "=" in initializations


If set to "True", align at the assignment operator "=" in initializations, e.g.:
var
Minimum: Integer = 0;
Max: Integer = 127;
Alignment of columns with ":" is defined separately under the setting "Align ":" before
type names", and when it is "True" it becomes:
var
Minimum: Integer = 0;
Max : Integer = 127;
The default setting is "False", which is also the recommended setting.

5.1.3 Align "=" in type declarations


If set to "True", must be aligned after "=" in declarations of types, for example:
type
pMinInfo = ^TMinInfo;
PMIN = ^TMin;
The default setting is "False", which is also the recommended setting.

5.1.4 Align assignment operators


If set to "True", must be adjusted according to the assignment operators ":=", e.g.:
Minimum := 1;
Max := 128;
The default setting is "False", which is also the recommended setting.

157
5.1.5 Align end-of-line comments
If set to "True", comments should be aligned at the end of lines, e.g.:
Minimum := 0; // aligned
Max := 127; // aligned
A := 63; { aligned }
// not aligned - this comment starts the line
B { not aligned - is not end-of-line comment } := 31;
The default setting is "False", which is also the recommended setting.

5.1.6 Align fields in properties


If set to "True", fields and methods must be adjusted for properties, e.g.:
property CustomStrings: TStrings
read GetCustomStrings
write SetCustomStrings
stored IsCustomStringsStored;
Note: This option only works if the option "Line breaks in Property declarations" defines
that each field is placed on a new line.
The default setting is "False", which is also the recommended setting.

5.1.7 Align type names


If set to "True", type names in "var" sections and records must be aligned, e.g.:
var
I: Integer;
Text: string;
Alignment after columns with ":" is defined by an option for "Align ":" before types", and if
it is "True", then it will look like this instead:
var
I : Integer;
Text: string;
The default setting is "False", which is also the recommended setting.

5.1.8 Align types of parameters


If set to "True", then the types of parameters must be adjusted:
procedure StrToInt(
S: string;
Default: Integer = 0);
Alignment after colons ":" is defined separately by an option for "Align ":" before type
names", and when it is "True" it becomes:

158
procedure StrToInt(
S : string;
Default: Integer = 0);
Note: This option only works if "One parameter per line in function definitions" defines
that each parameter is placed on a new line.
The default setting is "False", which is also the recommended setting.

5.2 General
These settings may affect the previously mentioned alignment settings.

5.2.1 Align ":" before type names


Defines whether columns with ":" should be aligned before the names of types. This set-
ting changes options for "Align types of parameters", "Align type names", and "Align "="
in initializations".
If "True", columns with ":" should be aligned along with the types:
I : Integer;
Text: string;
If "False", adjust only names for the types:
I: Integer;
Text: string;
The default setting is "False", which is also the recommended setting.

5.2.2 Alignment maximum column


Do not insert alignment with spaces after a given column. The default value is "60".

5.2.3 Maximum unaligned lines


This is the maximum number of unaligned lines of code allowed without ending the block
with an alignment of lines. This setting controls how the end of a block of aligned lines is
detected. When the value is zero, the alignment block is terminated by an unaligned line,
e.g., of a blank line.
The default value is "0".

Postscript
An effective use of Code Formatter must be absolutely flawless. Accidental reformatting of
otherwise correct stylized code constructs can render any attempt to encourage the use of
Code Formatter across a company or team quite pointless. Maybe Code Formatter is a
low priority at Embarcadero, but when we work with software quality in general and code
quality in particular, automation in measuring the code standard will make the process
within Quality Assurance much easier. Even if it was just a simple comparison of a for-
matted source code measured against an original file and interpreted in a few metrics.
159
Code quality is a major focus area because it shapes overall software quality. And quality
affects how secure, durable, and well-built our code assets are. Quality is essential for
most projects, and not least essential for projects with critical security systems, sensitive
information or handling large resources. A normal practice to measure software quality is
an assessment of the code against a standard.
Delphi has Audits and Metrics facilities that are not covered in this manual. Audits can
support a company's standards and conventions, record real metrics, and help improve
work. Facilitation of code metrics will be in accordance with Best Practices within Soft-
ware Quality Assurance, including quality of code:

• Choose a standard style guide.


• Use code metrics before code reviews.
• Follow best practices in code reviews.
• Follow the philosophies behind refactoring.

160
Chapter 10
Epilogue
With a well-functioning Code Formatter, it will of course not be a problem to maintain a
personal stylization of code for your own working copy. We can use Code Formatter auto-
mation on local copies, just as we can also use Code Formatter on the source code when
preparing the files for commit and code reviews. Standalone Formatter can also be used
in a test environment, so that quality of code style can also be incorporated into auto-
mated tests. But it is not that easy when Code Formatter is not as well-functioning in all
areas as style guides and Coding Best Practices suggest.
Code Formatter could have ensured a smooth transition for professionals coming from a
project that followed a different style guide, thus not having to be challenged by another
established standard and avoiding recommending developers to adjust their coding style.
Most professionals adapt, but many need time to adapt to a style guide that is far from
what they consider normal or familiar.
But it requires a well-running Code Formatter. And otherwise, we have to appeal to our
teams to write in accordance with a style guide manually from day one. I'm not sure there
have been any real improvements to the Code Formatter as a feature since 2010, other
than maybe tweaks or fixes so it could be released with newer Delphi versions. Format-
ter.exe follows the same product version as bds.exe, but Code Formatter doesn't
seem to have changed, aside from this.

161

You might also like