Unit: what changed
Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.
Title: Unit
| Old | New | Line | |
|---|---|---|---|
| 1 | + | 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]]. `Unit` is a [[Reserved word|reserved word]]. It must appear before anything in the unit except comments. | |
| 2 | + | ||
| 3 | + | ## Purpose | |
| 4 | + | ||
| 5 | + | 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. | |
| 6 | + | ||
| 7 | + | 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. | |
| 8 | + | ||
| 9 | + | 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. | |
| 10 | + | ||
| 11 | + | 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|uses statement]] (but linking is done without the need to write a makefile as in C). | |
| 12 | + | ||
| 13 | + | 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 `common` [[Keyword|keyword]] in the [[Fortran]] programming language. | |
| 14 | + | ||
| 15 | + | ## Format | |
| 16 | + | ||
| 17 | + | 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: | |
| 18 | + | ||
| 19 | + | ``` pascal | |
| 20 | + | unit minimalunit; | |
| 21 | + | interface | |
| 22 | + | // here comes stuff that the unit publicly offers | |
| 23 | + | implementation | |
| 24 | + | // here comes the implementation of offered stuff and | |
| 25 | + | // optionally internal stuff (only known in the unit) | |
| 26 | + | end. | |
| 27 | + | ``` | |
| 28 | + | ||
| 29 | + | where the part after [[Interface|interface corresponds]] to the `public`-part of other languages and [[Implementation|implementation]] does so to `private`. | |
| 30 | + | ||
| 31 | + | A more advanced basic structure is: | |
| 32 | + | ||
| 33 | + | ``` pascal | |
| 34 | + | unit advancedunit; | |
| 35 | + | interface | |
| 36 | + | ||
| 37 | + | implementation | |
| 38 | + | ||
| 39 | + | initialization | |
| 40 | + | // here may be placed code that is | |
| 41 | + | // executed as the unit gets loaded | |
| 42 | + | ||
| 43 | + | finalization | |
| 44 | + | // code executed at program end | |
| 45 | + | ||
| 46 | + | end. | |
| 47 | + | ``` | |
| 48 | + | ||
| 49 | + | The optional [[Initialization|initialization]] and [[Finalization|finalization]] blocks may be followed by code that is executed on program start/end. | |
| 50 | + | ||
| 51 | + | ### Detailed unit example | |
| 52 | + | ||
| 53 | + | A step-by-step example: | |
| 54 | + | ||
| 55 | + | ``` pascal | |
| 56 | + | unit randomunit; | |
| 57 | + | // this unit does something | |
| 58 | + | ||
| 59 | + | // public - - - - - - - - - - - - - - - - - - - - - - - - - | |
| 60 | + | interface | |
| 61 | + | ||
| 62 | + | type | |
| 63 | + | // the type TRandomNumber gets globally known | |
| 64 | + | // since it is included somewhere (uses-statement) | |
| 65 | + | TRandomNumber = integer; | |
| 66 | + | ||
| 67 | + | // of course the const- and var-sections are possible, too | |
| 68 | + | ||
| 69 | + | // a list of procedure/function signatures makes | |
| 70 | + | // them usable from outside of the unit | |
| 71 | + | function getRandomNumber(): TRandomNumber; | |
| 72 | + | ||
| 73 | + | // an implementation of a function/procedure | |
| 74 | + | // must not be in the interface-part | |
| 75 | + | ||
| 76 | + | // private - - - - - - - - - - - - - - - - - - - - - - - - - | |
| 77 | + | implementation | |
| 78 | + | ||
| 79 | + | var | |
| 80 | + | // var in private-part | |
| 81 | + | // => only modifiable inside from this unit | |
| 82 | + | chosenRandomNumber: TRandomNumber; | |
| 83 | + | ||
| 84 | + | function getRandomNumber(): TRandomNumber; | |
| 85 | + | begin | |
| 86 | + | // return value | |
| 87 | + | getRandomNumber := chosenRandomNumber; | |
| 88 | + | end; | |
| 89 | + | ||
| 90 | + | // initialization is the part executed | |
| 91 | + | // when the unit is loaded/included | |
| 92 | + | initialization | |
| 93 | + | begin | |
| 94 | + | // choose our random number | |
| 95 | + | chosenRandomNumber := 3; | |
| 96 | + | // chosen by fair-dice-roll | |
| 97 | + | // guaranteed to be random | |
| 98 | + | end; | |
| 99 | + | ||
| 100 | + | // finalization is executed at program end | |
| 101 | + | finalization | |
| 102 | + | begin | |
| 103 | + | // this unit says 'bye' at program halt | |
| 104 | + | writeln('bye'); | |
| 105 | + | end; | |
| 106 | + | ||
| 107 | + | // initialization and finalization | |
| 108 | + | // are executed at most _once_ | |
| 109 | + | // during the entire runtime of a program | |
| 110 | + | end. | |
| 111 | + | ``` | |
| 112 | + | ||
| 113 | + | To include a unit just use the `uses`-statement. | |
| 114 | + | ||
| 115 | + | ``` pascal | |
| 116 | + | program chooseNextCandidate; | |
| 117 | + | uses | |
| 118 | + | // include a unit | |
| 119 | + | randomunit; | |
| 120 | + | ||
| 121 | + | begin | |
| 122 | + | writeln('next candidate: no. ' + getRandomNumber()); | |
| 123 | + | end. | |
| 124 | + | ``` | |
| 125 | + | ||
| 126 | + | When compiling, FPC checks this program for unit dependencies. It has to be able to find the unit “randomunit”. | |
| 127 | + | ||
| 128 | + | 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. | |
| 129 | + | ||
| 130 | + | ## Unit precedence | |
| 131 | + | ||
| 132 | + | 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. | |
| 133 | + | ||
| 134 | + | 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. | |
| 135 | + | ||
| 136 | + | ``` pascal | |
| 137 | + | unit interestCalculations; | |
| 138 | + | ||
| 139 | + | interface | |
| 140 | + | ||
| 141 | + | type | |
| 142 | + | basisType = currency; | |
| 143 | + | ||
| 144 | + | implementation | |
| 145 | + | ||
| 146 | + | end. | |
| 147 | + | ``` | |
| 148 | + | ||
| 149 | + | Specifying the unit of declaration explicitly: | |
| 150 | + | ||
| 151 | + | ``` pascal | |
| 152 | + | program interestCalculator; | |
| 153 | + | ||
| 154 | + | uses | |
| 155 | + | interestCalculations; | |
| 156 | + | ||
| 157 | + | type | |
| 158 | + | // we already loaded a declaration of "basisType" | |
| 159 | + | // from the interestCalculations unit, but we're | |
| 160 | + | // re-declaring it here again ("shadowing") | |
| 161 | + | basisType = extended; | |
| 162 | + | ||
| 163 | + | var | |
| 164 | + | // last declaration wins: originalCapital is an extended | |
| 165 | + | originalCapital: basisType; | |
| 166 | + | // specify a scope to use the declaration valid there | |
| 167 | + | monthlyMargin: interestCalculations.basisType; | |
| 168 | + | ||
| 169 | + | begin | |
| 170 | + | end. | |
| 171 | + | ``` | |
| 172 | + | ||
| 173 | + | Note, the `interestCalculations` unit will still perform its own calculations with its own `basisType` (here [[Currency|currency]]). You can only alter (“shadow”) declarations in the current [[Scope|scope]] (and descending). | |
| 174 | + | ||
| 175 | + | ## See also | |
| 176 | + | ||
| 177 | + | - [“Unit scope” in the “reference guide”](https://www.freepascal.org/docs-html/ref/refsu102.html) (FPC HTML documentation) | |
| 178 | + | - [“Compiling a unit” in the “users's guide”](https://www.freepascal.org/docs-html/user/userse11.html) (FPC HTML documentation) | |
| 179 | + | - [§ “Units” in the WikiBook “Pascal Programming”](https://en.wikibooks.org/wiki/Pascal_Programming/Units) | |
| 180 | + | - [[Unit not found - How to find units]] | |
| 181 | + | ||
| 182 | + | --- | |
| 183 | + | *From the Free Pascal wiki, page "Unit", as it stood on 2022-01-02 after a change by Kai Burghardt, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* |
