Pascal is a procedural programming language designed in 1968-1969 and published in 1970 by Niklaus Wirth as a small, efficient language intended to encourage good programming practices using structured programming and data structuring.
Use this file to discover all available pages before exploring further.
Pascal Anti-Patterns Overview
Pascal, despite being designed to encourage good programming practices, has several common anti-patterns that can lead to maintainability problems and bugs. Here are the most important anti-patterns to avoid when writing Pascal code.
Using GOTO Statements
(* Anti-pattern: Using GOTO statements *)procedure ProcessData;vari: Integer;begini := 1;StartLoop:if i > 100 thengoto EndLoop;WriteLn('Processing item ', i);i := i + 1;goto StartLoop;EndLoop:WriteLn('Processing complete');end;(* Better approach: Use structured control flow *)procedure ProcessData;vari: Integer;beginfor i := 1 to 100 dobeginWriteLn('Processing item ', i);end;WriteLn('Processing complete');end;
Avoid using GOTO statements, which make code difficult to understand and maintain. Use structured control flow constructs like for, while, repeat-until, and if-then-else instead.
Leverage Pascal’s strong typing system rather than using variant records or other techniques that circumvent type safety. In modern Object Pascal, use interfaces, classes, or generics for type-safe polymorphism.
Using Global Variables
(* Anti-pattern: Using global variables *)varCurrentUser: String;LoggedIn: Boolean;ErrorCount: Integer;procedure Login(Username, Password: String);beginif ValidateCredentials(Username, Password) thenbeginCurrentUser := Username;LoggedIn := True;ErrorCount := 0;endelsebeginLoggedIn := False;Inc(ErrorCount);end;end;procedure ProcessUserData;beginif not LoggedIn thenExit;(* Process data for CurrentUser *)end;(* Better approach: Use parameter passing and return values *)typeTUserSession = recordUsername: String;LoggedIn: Boolean;ErrorCount: Integer;end;function Login(Username, Password: String): TUserSession;varSession: TUserSession;beginSession.Username := '';Session.LoggedIn := False;Session.ErrorCount := 0;if ValidateCredentials(Username, Password) thenbeginSession.Username := Username;Session.LoggedIn := True;endelsebeginInc(Session.ErrorCount);end;Result := Session;end;procedure ProcessUserData(const Session: TUserSession);beginif not Session.LoggedIn thenExit;(* Process data for Session.Username *)end;
Avoid using global variables, which create hidden dependencies and make code harder to understand, test, and maintain. Pass data explicitly through parameters and return values.
Not Using Proper Error Handling
(* Anti-pattern: Poor error handling *)procedure ReadDataFromFile(FileName: String);varF: TextFile;Line: String;beginAssignFile(F, FileName);Reset(F); (* May raise an exception if file doesn't exist *)while not Eof(F) dobeginReadLn(F, Line);ProcessLine(Line);end;CloseFile(F);end;(* Better approach: Proper error handling *)procedure ReadDataFromFile(FileName: String);varF: TextFile;Line: String;beginAssignFile(F, FileName);tryReset(F);while not Eof(F) dobegin ReadLn(F, Line); ProcessLine(Line);end;excepton E: EInOutError do WriteLn('File error: ', E.Message);on E: Exception do WriteLn('Error: ', E.Message);finallyCloseFile(F);end;end;
Use proper error handling with try-except-finally blocks (in modern Pascal) to handle exceptions and ensure resources are properly cleaned up, even when errors occur.
Using Magic Numbers
(* Anti-pattern: Using magic numbers *)procedure CalculateArea(Radius: Real);varArea: Real;beginArea := 3.14159 * Radius * Radius;WriteLn('Area: ', Area:0:2);end;procedure ResizeArray(var Arr: array of Integer);varNewArr: array of Integer;i: Integer;beginSetLength(NewArr, Length(Arr) * 2);for i := 0 to Length(Arr) - 1 doNewArr[i] := Arr[i];Arr := NewArr;end;(* Better approach: Use named constants *)constPI = 3.14159;ARRAY_GROWTH_FACTOR = 2;procedure CalculateArea(Radius: Real);varArea: Real;beginArea := PI * Radius * Radius;WriteLn('Area: ', Area:0:2);end;procedure ResizeArray(var Arr: array of Integer);varNewArr: array of Integer;i: Integer;beginSetLength(NewArr, Length(Arr) * ARRAY_GROWTH_FACTOR);for i := 0 to Length(Arr) - 1 doNewArr[i] := Arr[i];Arr := NewArr;end;
Avoid using magic numbers (hardcoded numeric literals) in your code. Use named constants to make your code more readable and maintainable.
Not Using Proper Resource Management
(* Anti-pattern: Poor resource management *)procedure ProcessFile(FileName: String);varF: TextFile;beginAssignFile(F, FileName);Reset(F);(* Process file... *)(* What if an exception occurs before this point? *)CloseFile(F);end;(* Better approach: Proper resource management *)procedure ProcessFile(FileName: String);varF: TextFile;beginAssignFile(F, FileName);tryReset(F);(* Process file... *)finallyCloseFile(F);end;end;
Always ensure that resources (files, memory, etc.) are properly released, even when exceptions occur. Use try-finally blocks to guarantee cleanup code is executed.
Not Using Proper Data Structures
(* Anti-pattern: Using arrays for dynamic collections *)procedure ProcessItems;varItems: array[1..100] of String; (* Fixed size *)Count: Integer;i: Integer;beginCount := 0;(* Add items *)while not EndOfInput dobeginInc(Count);if Count > 100 thenbegin WriteLn('Too many items!'); Exit;end;Items[Count] := ReadItem();end;(* Process items *)for i := 1 to Count doProcessItem(Items[i]);end;(* Better approach: Use dynamic data structures *)procedure ProcessItems;varItems: TStringList; (* Dynamic size *)i: Integer;beginItems := TStringList.Create;try(* Add items *)while not EndOfInput do Items.Add(ReadItem());(* Process items *)for i := 0 to Items.Count - 1 do ProcessItem(Items[i]);finallyItems.Free;end;end;
Use appropriate data structures for your needs. In modern Pascal, use dynamic arrays, lists, dictionaries, and other collection classes instead of fixed-size arrays.
Not Using Units for Code Organization
(* Anti-pattern: Everything in one file *)program MonolithicApp;(* Hundreds of types, variables, and procedures all in one file *)begin(* Main program code *)end.(* Better approach: Use units for modular code organization *)unit UserManagement;interfacetypeTUser = recordUsername: String;Email: String;end;function CreateUser(const Username, Email: String): TUser;procedure SaveUser(const User: TUser);function FindUser(const Username: String): TUser;implementation(* Implementation of user management functions *)end.unit FileHandling;interfaceprocedure SaveToFile(const FileName, Content: String);function LoadFromFile(const FileName: String): String;implementation(* Implementation of file handling functions *)end.program ModularApp;usesUserManagement, FileHandling;begin(* Main program code using the units *)end.
Organize your code into units (modules) with clear responsibilities. This improves maintainability, reusability, and compilation times.
Not Using Strong Type Definitions
(* Anti-pattern: Weak type definitions *)procedure ProcessPerson(Name: String; Age: Integer; Height: Real);begin(* What if parameters are passed in the wrong order? *)WriteLn('Name: ', Name, ', Age: ', Age, ', Height: ', Height:0:2);end;(* Usage *)ProcessPerson('John', 25, 1.75); (* Correct *)ProcessPerson(25, 'John', 1.75); (* Compiler won't catch this error! *)(* Better approach: Use strong type definitions *)typeTPersonName = String;TAge = Integer;THeight = Real;TPerson = recordName: TPersonName;Age: TAge;Height: THeight;end;procedure ProcessPerson(const Person: TPerson);beginWriteLn('Name: ', Person.Name, ', Age: ', Person.Age, ', Height: ', Person.Height:0:2);end;(* Usage *)varPerson: TPerson;beginPerson.Name := 'John';Person.Age := 25;Person.Height := 1.75;ProcessPerson(Person);end;
Use strong type definitions and structured data types to make your code more type-safe and self-documenting.
Not Using Function Results
(* Anti-pattern: Using var parameters instead of function results *)procedure CalculateSum(A, B: Integer; var Result: Integer);beginResult := A + B;end;(* Usage *)varX, Y, Sum: Integer;beginX := 5;Y := 10;CalculateSum(X, Y, Sum);WriteLn('Sum: ', Sum);end;(* Better approach: Use function results *)function CalculateSum(A, B: Integer): Integer;beginResult := A + B;end;(* Usage *)varX, Y: Integer;beginX := 5;Y := 10;WriteLn('Sum: ', CalculateSum(X, Y));end;
Use function return values instead of var parameters for outputs. This makes the code more readable and allows for function composition.
Not Using Proper String Handling
(* Anti-pattern: Using fixed-length strings and manual concatenation *)typeTName = array[1..50] of Char;procedure FormatName(var FullName: TName; FirstName, LastName: TName);vari, j: Integer;begin(* Clear the destination *)for i := 1 to 50 doFullName[i] := ' ';(* Copy first name *)i := 1;while (i <= 50) and (FirstName[i] <> ' ') dobeginFullName[i] := FirstName[i];Inc(i);end;(* Add space *)FullName[i] := ' ';Inc(i);(* Copy last name *)j := 1;while (i <= 50) and (j <= 50) and (LastName[j] <> ' ') dobeginFullName[i] := LastName[j];Inc(i);Inc(j);end;end;(* Better approach: Use dynamic strings *)function FormatName(const FirstName, LastName: String): String;beginResult := FirstName + ' ' + LastName;end;
Use modern string types and operations instead of fixed-length character arrays and manual string manipulation. This makes your code more readable and less error-prone.
Not Using Proper Documentation
(* Anti-pattern: Poor or no documentation *)function CalculateValue(A, B, C: Integer): Integer;beginResult := A * B + C;end;(* Better approach: Proper documentation *)(** Calculates a weighted sum of two values plus an offset.** @param A The first value to be multiplied.* @param B The second value to be multiplied.* @param C The offset to be added after multiplication.* @return The result of A * B + C.*)function CalculateValue(A, B, C: Integer): Integer;beginResult := A * B + C;end;
Document your code with comments that explain the purpose, parameters, return values, and any important details or assumptions. This makes your code more maintainable and easier for others to understand.
In modern Object Pascal, use object-oriented design principles like encapsulation, inheritance, and polymorphism to create more maintainable and extensible code.