-
Notifications
You must be signed in to change notification settings - Fork 0
RADProgrammer Style Guide Other Guidance
Ensure your new code has passed through the Automatic CodeFormatter with the RADProgrammer custom profile active before committing the code to the main developer branch.
Case typically does not matter in Pascal, however code should always be written in a case-sensitive matter for readability and consistency purposes
-
Consider
with
to be deprecated and not used -
Consider
goto
as usually worse thanwith
but can, on rare occasions, simplify very ugly code -
Consider the System.DateUtil methods
YearsBetween
,MonthsBetween
,YearSpan
, andMonthSpan
as deprecated and use alternatives -
Do not utilize
inline variables
(first introduced in 10.3 in November 2018) until the tooling catches up. Some examples include:- Formatting:
- Refactoring:
- RSP-30155 When using inline variable, Refactor->Rename and Declare Variable functions do not work properly
- RSP-32507 Inline variable breaks the Methods drop-down box in Navigation Toolbar Marked as "Fixed" in RAD Studio 11, Release 3
- RSP-33176 Extract method refactoring broken by inline var definition
- RSP-33365 In-block variables break the "Find references"
- RSP-36998 Refactoring fails when using inline var delcarations
- Selection Expansion: (Ctrl-W)
- Debugging:
- RSP-23096 Incorrect debugger values
- RSP-23056 Repeated inline var declaration causes repeated debugger variable display
- RSP-37209 Breakpoints of inline method are shown active but are not hit
- RSP-39997 Debugger seems not able to handle trivial Delphi program using inline variable declarations Marked as "Fixed" in RAD Studio 12 Athens
- RSS-898 Delphi Debugger shows wrong values
- RSS-1114 Wrong inline variable evaluation from debugger, if it's declared multiple times
- Type Inference:
- Other:
- RSS-2613 Anonymous Method is called differently depending on whether it is declared as an Inline Variable or not
- RSP-25799 TDateTime is wrongly inferred in inline vars
- RSP-44148 Inline variable declarations do not work after a Label
- RSP-36150 Memory Leak: Inline interface variables in generic method Marked as "Fixed" in RAD Studio 11, Release 2
- RSS-1336 Delphi LSP crashed by inline variable
-
Only sparingly use the new feature
Multi-line string literals
introduced in Delphi 12 due to tooling failures. If the tooling failures take as long as inline-variables, consider this feature as broken for at least the next few years.
Code that is automatically generated by the IDE does not need to be manually reformatted to match these style guidelines (such as renaming parameter names and manually re-ordering of class methods automatically added to the interface section.) Auto-generated code is expected to be formatted in a particular fashion and can be left as-is.
- Be intentional on the use of the
else
clause. Typically, the else clause should be used in the event that the selected expression was not expected. This is easily demonstrated by using an enumerated type in a case statement as in the example below
TMyExampleEnum = (Enum1, Enum2, Enum3);
...
// This is a common implementation for handling the three options currently available
// This code does not age well when a new TMyExampleEnum value is added at some point in the future:
case vMyValue of
Enum1: DoOne();
Enum2: DoTwo();
else
DoThree();
end;
// This code is defensive and will alert on a new value:
case vMyValue of
Enum1: DoOne();
Enum2: DoTwo();
Enum3: DoThree();
else
Assert(False, 'Invalid TMyExampleEnum value');
end;
- Wrapping very long lines at an nondescript right margin may signify that refactoring is needed
- Using page-up and page-down in a single method may signify that refactoring is needed
- Favor composition over inheritance when building your classes
- Each line should contain at most one statement
// This is technically valid code
Statement1; Statement2;
// Better:
Statement1;
Statement2;
- Always end a statement with a semicolon.
// this is valid code, but you should always include the final semicolon in a code block
begin
Statement1;
Statement2
end;
// Better:
begin
Statement1;
Statement2;
end;
- Utilize the
const
reserved word for read-only parameters to allow the compiler to optimize structured and string parameters.
- Outside of Guard Clauses, use
Exit
sparingly -
Guard Clauses
can be used to reduce nesting
// Without guard clause
function Combine(SomeThing:String; SomeOther:String):String;
begin
if (SomeThing <> '') then
begin
if (SomeOther <> '') then
begin
//combine
...
end
else
begin
Result := SomeThing;
end
else
begin
Result := SomeOther;
end;
end;
// Guard clauses can reduce complexity
function Combine(SomeThing:String; SomeOther:String):String;
begin
if SomeThing = '' then Exit(SomeOther);
if SomeOther = '' then Exit(SomeThing);
//combine
...
end;
- Do not access fields directly in code, rather read and write field values utilizing their Property references with the possible exception of inside the parent class constructor.
- Hard coded numbers (other than 0 and 1) and strings should be defined as named constants or resource strings. (Passwords, cryptographic keys or other credentials should never be embedded in code.)
- The items within a
uses
clause are usually grouped by scope such as listing RTL (System, Platform) units first, and then System Library (Data, Soap, Xml...), Framework (VCL/FMX), Third Party libraries and components, units shared across projects, and project-specific units listed last.
If a method has no parameters, it is preferred to utilize a parenthesis as in the following example:
if i > 1 then
begin
CallSomeMethod(); //parenthesis not required, but recommended
end
...
- Unless types are referenced in the unit's Interface section, always add units to the
uses
clause in the Implementation section which helps to improve project build times and minimize circular dependencies.
- In general, write code to check for the positive case rather than negative
// Negative
if not Good then
begin
DoBad;
end
else
begin
DoGood;
end;
// Positive
if Good then
begin
DoGood;
end
else
begin
DoBad;
end;
- Code written for Unit, Integration, Performance, Security, and other testing purposes should generally follow all Style Guide rules
- When modifying code that also needs to be refactored, first refactor the code and execute the tests to validate the changes made, commit those refactoring changes and only then proceed to modify the code logic. Refactoring-only changes should be separate commits. (Note: this same rule applies to reformatting a unit.)