Blog
All Blog Posts | Next Post | Previous PostObject Pascal: Declaring Units
Tuesday, March 20, 2018
Declaring units in a specific order in code would facilitate the code maintenance in the future.
IntroductionWhen we're organizing our things, we tend to keep closer to us all objects that we use daily, right?
So it should be with the units of a project.
The order that units appear in the code could facilitate or not the maintenance.
In that article, I will show you what order I use to declare units in my own projects.
CompilerThe units, also known as modules, compose the projects.
Every project must be divided into logical units and make that division it's not always easy, because it involves an abstract and logical level of thinking.
After dividing the project units, we also need to concern with third-party units.
Nowadays it's almost mandatory that we use lib's and frameworks. Mostly, they are Open Source projects.
Such third-party units make our work easier, as they already have ready-made artifacts that speed up the development of projects.
In addition to these third-party units, we also have the default units located in Run-time Library (RTL) or VCL/LCL, which have many interfaces, classes, functions, and artifacts, ready-to-use.
So, what order we should declare such units in our code?
Here is the order that I propose:
unit MyUnit; uses // 1. fpc/lazarus/delphi units, // 2. 3rd units, // 3. my open source units, // 4. project units
When the compiler starts parsing your code and it arrives at MyUnit
, it will read the units in the sequence in which they were declared there may be some optimization, but the important thing is the final result, which depends on the order above and the identifiers (classes, interfaces, functions/procedures, variables and constants) will be "stored in order" in which they were declared.
So, I propose to declare, initially, all units that are standard to the compiler and IDE. Then, all third-party units such as libs and frameworks. After, all units referring to your public projects, be them OpenSource or shared within sectors of your company. Finally, we declare all units of the project itself, that is, the project we are currently working on.
And why is this important?
The reason is because the compiler needs to know in which unit a particular artefact (class, function, etc) is located.
The rule is that:
If you have 3 units (Unit1
, Unit2
and Unit3
) and each has a class named TFoo
, the compiler will "inform" your code that TFoo
is located in the last declared unit.
For example:
uses Unit1, Unit3, Unit2;
Notice that I reversed the numerical order. First is 1, then 3, and finally 2.
Where is located TFoo
class when you'll use it in yourMyUnit
?
The answer is: In Unit2
.
Because it was declared by last.
Imagine that the compiler is putting a reference table into memory for all the identifiers it finds. First, it finds TFoo
when it reads Unit1
. Then, it finds it again when it reads Unit3
. At this point it overrides the reference that says that TFoo
is in Unit1
, because it is now in Unit3
. Finally, when it reads Unit2
the identifier is repositioned again.
If in that same MyUnit
I need to use TFoo
from Unit1
, I am required to qualify the class with the unit name instead of just using identifier:
Foo := Unit1.TFoo.Create...
You can see another example here
SectionsIn the Object Pascal language we have two places (sections) where we can declare the units that will be used.
We can declare in the interface section or in the implementation section.
Is it worth declaring Units in the implementation section?
In my opinion, no.
In doing so, you will have 2 places to organize the precedence of the Units, meaning you will have more work.
Because the Object Pascal language does not support Circular Reference between Units, one of the reasons for having the option to declare Units in the implementation section is to allow this bi-directional reference between them. However, this also indicates a bad design in the division of the project units.
ConclusionDefining the order of declaration of the units in each unit of your project can be extremely important to facilitate maintenance and organization.
As you add new identifiers, you will be sure that the compiler will give you "priority" to use the identifiers for your project, without having to prefix it with the unit name.
If you add some identifier and it conflicts with another unit that has the same name, simply prefix that identifier with the name of the unit, either from third parties or from the environment itself. However, this conflict will not exist in the identifiers of the units of your project.
Therefore, in your code, you should better "get closer" units that belong to the project, because they are more used, than from other auxiliary units.
See you.
Marcos Douglas B. Santos
This blog post has received 4 comments.
However, Pascal programmers don''t code like that. We can count just a few times that we used units as a namespace, right?
If that were mandatory by language design, then yes, there would be no problems.
Marcos Douglas B. Santos
Wagner R. Landgraf
Peter Davies
All Blog Posts | Next Post | Previous Post
If you ever get into a situation where the same class is declared in more that one unit and you end up using both units from the same code, the correct solution isn''t to mess with the unit order, it''s to use the full namespace when you specify the type in question (or function call, etc).
e.g.
var
foo: TFoo;
must be declared as
var
foo: Unit2.TFoo;
If you stick to that rule, you will NEVER have a problem with unit orders in your code.
Grobety Stephane