Understanding
Units can reference and depend on one another. When one unit references another, the referenced unit can be declared either in the interface section or solely in the implementation section. The differences between the two approaches are listed below:
Declared in the interface section (interface-side reference): You may define new public elements (procedures, custom types, etc.) exposed externally based on contents from the referenced unit, which will be accessible to all other units across the entire project.
Declared solely in the implementation section (implementation-side reference): Scope is restricted. Identifiers from the referenced unit can only be used within the implementation code of the current unit and cannot be accessed externally.
Example
This is merely a demonstration. Readers have not yet learned about classes, so focus only on grasping the underlying concept for now.
Create a new unit file named Classes.pas
unit Classes;
{$mode objfpc}{$H+}
interface
type
TObject=class;
TComponent=class(TObject)
constructor Create(AOwner:TComponent);virtual;
end;
TObject=class
destructor Destroy;virtual;
end;
implementation
constructor TComponent.Create(AOwner:TComponent);begin end;
destructor TObject.Destroy;begin end;
end.
Then reference this unit inside AnotherUnit.pas
unit AnotherUnit;
{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
interface
uses
Classes;
// The TComponent class is defined in the Classes unit, so Classes must be referenced in the interface section
procedure DoSomethingWithComponent(var C: TComponent);
implementation
uses SysUtils; // SysUtils referenced only in the implementation section
procedure DoSomethingWithComponent(var C: TComponent);
begin
// FreeAndNil originates from SysUtils and is only invoked within implementation code; referencing it solely in implementation is sufficient
FreeAndNil(C);
end;
end.Code language: JavaScript (javascript)
Notes
1 Bidirectional circular dependencies are forbidden in the interface section
Two units are not allowed to mutually reference each other within their respective interface sections simultaneously.
Principle: When parsing a unit’s interface, the compiler must fully resolve all dependent units listed in the unit’s uses interface clause first. Pascal adheres strictly to this rule, delivering two major benefits:
Faster compilation speed; the compiler automatically determines which units require recompilation without manual maintenance of complex Makefile build scripts. Full-project recompilation is unnecessary after code edits, while guaranteeing synchronized updates for all dependencies.
2 Circular dependencies are permitted in the implementation section
A circular dependency is valid as long as at least one side references the other unit exclusively inside the implementation section.
Example: Unit A references Unit B in its interface section, while Unit B references Unit A only in its implementation section. This bidirectional circular structure is fully supported by the compiler.