Difference between revisions of "Unit"

From Lazarus wiki
Jump to navigationJump to search
(→‎Read more: "See also" is used much more in this and other wikis than "Read more" Fixed hyperlink.)
(partially undo revision 024573 by Rfc1394 (talk): change misleading)
 
(17 intermediate revisions by 6 users not shown)
Line 1: Line 1:
 
{{Unit}}
 
{{Unit}}
  
A '''unit''' is a [[Source code|source code]] file (or the [[Binary|binary]] compiled from that [[File|file]]) which was written using the [[Pascal]] programming language, and that is designed to be a single module in an [[Application|application]] or an [[Object module|object module]].  
+
A <syntaxhighlight lang="pascal" inline>unit</syntaxhighlight> is a [[Source code|source code]] file (or the [[Binary|binary]] compiled from that [[File|file]]) which was written using the [[Pascal]] programming language, and that is designed to be a single module in an [[Application|application]] or an [[Object module|object module]].
 +
<syntaxhighlight lang="pascal" inline>Unit</syntaxhighlight> is a [[Reserved word|reserved word]]. It must appear before anything in the unit except comments.
  
== Aim ==
+
== Purpose ==
A unit may be used where functionality needs to be provided to an application program or to other units. It allows writing code that performs that functionality once and have it used in many places.
+
A unit may be used where functionality needs to be provided to an application program or to other units.
 +
It allows writing code that performs that functionality once and have it used in many places.
 
This can reduce the possibility of errors and increase code reusage.
 
This can reduce the possibility of errors and increase code reusage.
  
A binary unit may be used where a unit author wishes to provide certain functionality to be used in a Pascal program but does not wish to provide the source code that performs that functionality.
+
A binary unit may be used where a unit author wishes to provide certain functionality to be used in a Pascal [[Program|program]] but does not wish to provide the source code that performs that functionality.
  
 
Units were also used on older versions of Pascal when it was necessary on computers with limited resources to be able to load [[Routine|routines]] as needed rather than keeping every routine of the [[Executable program|executable program]] in memory all of the time.
 
Units were also used on older versions of Pascal when it was necessary on computers with limited resources to be able to load [[Routine|routines]] as needed rather than keeping every routine of the [[Executable program|executable program]] in memory all of the time.
A unit that needs to access e.&nbsp;g.&nbsp;[[Procedure|procedures]] and [[Data type|data types]] in another unit must specify those units it needs to access in a [[Uses]] statement (but linking is done without the need to write a makefile as in C).
 
  
A unit may also be used to declare a series of global [[Const|constants]] or [[Global_variables|variables]] for use by the entire application, without actually containing any executable code.
+
A unit or program that needs to access the [[Procedure|procedures]] and [[Data type|data types]] in another unit must specify the units it needs to access them in a [[Uses|<syntaxhighlight lang="pascal" inline>uses</syntaxhighlight> statement]] (but linking is done without the need to write a makefile as in C).
This is similar to the <code>common</code> keyword in the Fortran programming language.
+
 
 +
A unit may also be used to declare a series of global [[Const|constants]] or [[Global variables|variables]] for use by the entire application, without actually containing any executable code.
 +
This is similar to the <syntaxhighlight lang="fortran" inline>common</syntaxhighlight> [[Keyword|keyword]] in the [[Fortran]] programming language.
  
 
== Format ==
 
== Format ==
A unit is defined with the ''unit'' keyword followed by the unit-identifier.
+
A unit is defined with the <syntaxhighlight lang="pascal" inline>unit</syntaxhighlight> keyword followed by the unit-identifier.
 
The unit-identifier (in the following example the unit's name is “minimalunit”) should match the filename it is written in.
 
The unit-identifier (in the following example the unit's name is “minimalunit”) should match the filename it is written in.
 
A minimal working example (which does nothing) is:
 
A minimal working example (which does nothing) is:
<syntaxhighlight>
+
 
 +
<syntaxhighlight lang="pascal">
 
unit minimalunit;
 
unit minimalunit;
 
interface
 
interface
(* here comes stuff that the unit publicly offers *)
+
// here comes stuff that the unit publicly offers
 
implementation
 
implementation
(* here comes the implementation of offered stuff and *)
+
// here comes the implementation of offered stuff and
(* optionally internal stuff (only known in the unit) *)
+
// optionally internal stuff (only known in the unit)
 
end.
 
end.
 
</syntaxhighlight>
 
</syntaxhighlight>
where the part after ''interface'' corresponds to the ''public''-part of other languages and ''implementation'' does so to ''private''.
 
  
A more advanced basic structure is
+
where the part after [[Interface|<syntaxhighlight lang="pascal" inline>interface</syntaxhighlight> ]]corresponds to the <syntaxhighlight lang="java" inline>public</syntaxhighlight>-part of other languages and [[Implementation|<syntaxhighlight lang="pascal" inline>implementation</syntaxhighlight>]] does so to <syntaxhighlight lang="java" inline>private</syntaxhighlight>.
<syntaxhighlight>
+
 
 +
A more advanced basic structure is:
 +
 
 +
<syntaxhighlight lang="pascal">
 
unit advancedunit;
 
unit advancedunit;
 
interface
 
interface
Line 38: Line 44:
  
 
initialization
 
initialization
(* here may be placed code that is *)
+
// here may be placed code that is
(* executed as the unit gets loaded *)
+
// executed as the unit gets loaded
  
 
finalization
 
finalization
(* code executed at program end *)
+
// code executed at program end
  
 
end.
 
end.
 
</syntaxhighlight>
 
</syntaxhighlight>
The optional ''initialization'' and ''finalization'' blocks may be followed by code that is executed on program start/end.
+
 
 +
The optional [[Initialization|<syntaxhighlight lang="pascal" inline>initialization</syntaxhighlight>]] and [[Finalization|<syntaxhighlight lang="pascal" inline>finalization</syntaxhighlight>]] blocks may be followed by code that is executed on program start/end.
  
 
=== Detailed unit example ===
 
=== Detailed unit example ===
 
A step-by-step example:
 
A step-by-step example:
<syntaxhighlight>
+
 
 +
<syntaxhighlight lang="pascal">
 
unit randomunit;
 
unit randomunit;
(* this unit does something *)
+
// this unit does something
  
(* public *)
+
// public - - - - - - - - - - - - - - - - - - - - - - - - -
 
interface
 
interface
  
 
type
 
type
(* the type TRandomNumber gets globally known *)
+
// the type TRandomNumber gets globally known
(* since it is included somewhere (uses-statement) *)
+
// since it is included somewhere (uses-statement)
 
TRandomNumber = integer;
 
TRandomNumber = integer;
  
(* of course the const- and var-blocks are possible, too *)
+
// of course the const- and var-sections are possible, too
  
(* a list of procedure/function signatures makes *)
+
// a list of procedure/function signatures makes
(* them useable from outside of the unit *)
+
// them usable from outside of the unit
 
function getRandomNumber(): TRandomNumber;
 
function getRandomNumber(): TRandomNumber;
  
(* an implementation of a function/procedure *)
+
// an implementation of a function/procedure
(* must not be in the interface-part *)
+
// must not be in the interface-part
  
(* private *)
+
// private - - - - - - - - - - - - - - - - - - - - - - - - -
 
implementation
 
implementation
  
 
var
 
var
(* var in private-part *)
+
// var in private-part
(* => only modifiable inside from this unit *)
+
// => only modifiable inside from this unit
 
chosenRandomNumber: TRandomNumber;
 
chosenRandomNumber: TRandomNumber;
  
 
function getRandomNumber(): TRandomNumber;
 
function getRandomNumber(): TRandomNumber;
 
begin
 
begin
(* return value *)
+
// return value
 
getRandomNumber := chosenRandomNumber;
 
getRandomNumber := chosenRandomNumber;
 
end;
 
end;
  
(* initialization is the part executed *)
+
// initialization is the part executed
(* when the unit is loaded/included *)
+
// when the unit is loaded/included
 
initialization
 
initialization
 
begin
 
begin
(* choose our random number *)
+
// choose our random number
 
chosenRandomNumber := 3;
 
chosenRandomNumber := 3;
(* chosen by fair-dice-roll *)
+
// chosen by fair-dice-roll
(* guaranteed to be random *)
+
// guaranteed to be random
 
end;
 
end;
  
(* finalization is worked off at program end *)
+
// finalization is executed at program end
 
finalization
 
finalization
 
begin
 
begin
(* this unit says 'bye' at program halt *)
+
// this unit says 'bye' at program halt
 
writeln('bye');
 
writeln('bye');
 
end;
 
end;
 +
 +
// initialization and finalization
 +
// are executed at most _once_
 +
// during the entire runtime of a program
 
end.</syntaxhighlight>
 
end.</syntaxhighlight>
  
To include a unit just use the ''uses''-statement.
+
To include a unit just use the <syntaxhighlight lang="pascal" inline>uses</syntaxhighlight>-statement.
<syntaxhighlight>
+
<syntaxhighlight lang="pascal" highlight="2-4">
 
program chooseNextCandidate;
 
program chooseNextCandidate;
 
uses
 
uses
(* include a unit *)
+
// include a unit
 
randomunit;
 
randomunit;
  
Line 114: Line 126:
 
end.
 
end.
 
</syntaxhighlight>
 
</syntaxhighlight>
When compiling, FPC checks this program for unit dependencies. It has to be able to find the unit "randomunit".
 
  
The simplest way to satisfy this is to have a unit whose name matches the file name it is written in (appending .pas is OK and encouraged).
+
When compiling, FPC checks this program for unit dependencies.
 +
It has to be able to find the unit “randomunit”.
 +
 
 +
The simplest way to satisfy this is to have a unit whose name matches the file name it is written in (appending <tt>.pas</tt> is OK and encouraged).
 
The unit file may be in the same directory where the program source is in or in the unit path FPC looks for units.
 
The unit file may be in the same directory where the program source is in or in the unit path FPC looks for units.
  
 
== Unit precedence ==
 
== Unit precedence ==
When multiple units are described in a use clause, conflicts can occur with identifiers (procedures, types, functions etc) that have the same name in multiple units. In FPC, the last unit "wins" and provides the code for the unit.
+
When multiple units are described in a use clause, conflicts can occur with identifiers (procedures, types, functions etc.) that have the same name in multiple units.
 +
In FreePascal, the last unit “wins” and provides the code for the unit.
 +
 
 +
If you want to achieve a different behavior, you can explicitly prepend <tt>''unitname.''identifier</tt> to specify the unit you want to use, or reorder the units.
 +
The former is often the clearest option.
 +
 
 +
<syntaxhighlight lang="pascal">
 +
unit interestCalculations;
 +
 
 +
interface
 +
 
 +
type
 +
basisType = currency;
  
If you want to have different behaviour, you can explicity prepend ''unitname.''identifier to specify the unit you want to use, or reorder the units. The former is often the clearest option.
+
implementation
  
== See also ==
+
end.
 +
</syntaxhighlight>
 +
 
 +
Specifying the unit of declaration explicitly:
 +
 
 +
<syntaxhighlight lang="pascal">
 +
program interestCalculator;
 +
 
 +
uses
 +
interestCalculations;
 +
 
 +
type
 +
// we already loaded a declaration of "basisType"
 +
// from the interestCalculations unit, but we're
 +
// re-declaring it here again ("shadowing")
 +
basisType = extended;
 +
 
 +
var
 +
// last declaration wins: originalCapital is an extended
 +
originalCapital: basisType;
 +
// specify a scope to use the declaration valid there
 +
monthlyMargin: interestCalculations.basisType;
 +
 
 +
begin
 +
end.
 +
</syntaxhighlight>
  
* [http://www.freepascal.org/docs-html/ref/refsu87.html Unit scope] (FPC html doc)
+
Note, the <tt>interestCalculations</tt> unit will still perform its own calculations with its own <tt>basisType</tt> (here [[Currency|<syntaxhighlight lang="pascal" inline>currency</syntaxhighlight>]]).
* [http://www.freepascal.org/docs-html/user/userse11.html Compiling a unit] (FPC html doc)
+
You can only alter (“shadow”) declarations in the current [[Scope|scope]] (and descending).
  
[[category:Pascal]]
+
== See also ==
 +
* [https://www.freepascal.org/docs-html/ref/refsu102.html “Unit scope” in the “reference guide”] (FPC HTML documentation)
 +
* [https://www.freepascal.org/docs-html/user/userse11.html “Compiling a unit” in the “users's guide”] (FPC HTML documentation)
 +
* [https://en.wikibooks.org/wiki/Pascal_Programming/Units § “Units” in the WikiBook “Pascal Programming”]
 +
* [[Unit not found - How to find units]]

Latest revision as of 12:56, 2 January 2022

Deutsch (de) English (en) español (es) suomi (fi) français (fr) português (pt) русский (ru)

A unit is a source code file (or the binary compiled from that file) which was written using the Pascal programming language, and that is designed to be a single module in an application or an object module. Unit is a reserved word. It must appear before anything in the unit except comments.

Purpose

A unit may be used where functionality needs to be provided to an application program or to other units. It allows writing code that performs that functionality once and have it used in many places. This can reduce the possibility of errors and increase code reusage.

A binary unit may be used where a unit author wishes to provide certain functionality to be used in a Pascal program but does not wish to provide the source code that performs that functionality.

Units were also used on older versions of Pascal when it was necessary on computers with limited resources to be able to load routines as needed rather than keeping every routine of the executable program in memory all of the time.

A unit or program that needs to access the procedures and data types in another unit must specify the units it needs to access them in a uses statement (but linking is done without the need to write a makefile as in C).

A unit may also be used to declare a series of global constants or variables for use by the entire application, without actually containing any executable code. This is similar to the common keyword in the Fortran programming language.

Format

A unit is defined with the unit keyword followed by the unit-identifier. The unit-identifier (in the following example the unit's name is “minimalunit”) should match the filename it is written in. A minimal working example (which does nothing) is:

unit minimalunit;
interface
	// here comes stuff that the unit publicly offers
implementation
	// here comes the implementation of offered stuff and
	// optionally internal stuff (only known in the unit)
end.

where the part after interface corresponds to the public-part of other languages and implementation does so to private.

A more advanced basic structure is:

unit advancedunit;
interface

implementation

initialization
	// here may be placed code that is
	// executed as the unit gets loaded

finalization
	// code executed at program end

end.

The optional initialization and finalization blocks may be followed by code that is executed on program start/end.

Detailed unit example

A step-by-step example:

unit randomunit;
// this unit does something

// public  - - - - - - - - - - - - - - - - - - - - - - - - -
interface

type
	// the type TRandomNumber gets globally known
	// since it is included somewhere (uses-statement)
	TRandomNumber = integer;

// of course the const- and var-sections are possible, too

// a list of procedure/function signatures makes
// them usable from outside of the unit
function getRandomNumber(): TRandomNumber;

// an implementation of a function/procedure
// must not be in the interface-part

// private - - - - - - - - - - - - - - - - - - - - - - - - -
implementation

var
	// var in private-part
	// => only modifiable inside from this unit
	chosenRandomNumber: TRandomNumber;

function getRandomNumber(): TRandomNumber;
begin
	// return value
	getRandomNumber := chosenRandomNumber;
end;

// initialization is the part executed
// when the unit is loaded/included
initialization
begin
	// choose our random number
	chosenRandomNumber := 3;
	// chosen by fair-dice-roll
	// guaranteed to be random
end;

// finalization is executed at program end
finalization
begin
	// this unit says 'bye' at program halt
	writeln('bye');
end;

// initialization and finalization
// are executed at most _once_
// during the entire runtime of a program
end.

To include a unit just use the uses-statement.

program chooseNextCandidate;
uses
	// include a unit
	randomunit;

begin
	writeln('next candidate: no. ' + getRandomNumber());
end.

When compiling, FPC checks this program for unit dependencies. It has to be able to find the unit “randomunit”.

The simplest way to satisfy this is to have a unit whose name matches the file name it is written in (appending .pas is OK and encouraged). The unit file may be in the same directory where the program source is in or in the unit path FPC looks for units.

Unit precedence

When multiple units are described in a use clause, conflicts can occur with identifiers (procedures, types, functions etc.) that have the same name in multiple units. In FreePascal, the last unit “wins” and provides the code for the unit.

If you want to achieve a different behavior, you can explicitly prepend unitname.identifier to specify the unit you want to use, or reorder the units. The former is often the clearest option.

unit interestCalculations;

interface

type
	basisType = currency;

implementation

end.

Specifying the unit of declaration explicitly:

program interestCalculator;

uses
	interestCalculations;

type
	// we already loaded a declaration of "basisType"
	// from the interestCalculations unit, but we're
	// re-declaring it here again ("shadowing")
	basisType = extended;

var
	// last declaration wins: originalCapital is an extended
	originalCapital: basisType;
	// specify a scope to use the declaration valid there
	monthlyMargin: interestCalculations.basisType;

begin
end.

Note, the interestCalculations unit will still perform its own calculations with its own basisType (here currency). You can only alter (“shadow”) declarations in the current scope (and descending).

See also