Object Pascal: Declaring Units

Bookmarks: 

Tuesday, March 20, 2018

Unsplash image

Declaring units in a specific order in code would facilitate the code maintenance in the future.

Introduction

When 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.

Compiler

The 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

Sections

In 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.

Conclusion

Defining 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


Bookmarks: 

This blog post has received 4 comments.


1. Thursday, March 22, 2018 at 11:19:27 AM

While what you suggest has some value, I think it''s a case where you''re fixing the symptom instead of the problem:

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


2. Thursday, March 22, 2018 at 2:00:40 PM

@Grobety you''re right.
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


3. Thursday, March 22, 2018 at 2:58:24 PM

@Stephane, such prefix with unit name is mentioned in the blog post. The problem is when you do not know (or forget) that the units you are using have classes with the same name. So it''s not always you will remember to prefix the type name. Thus following that order suggestion will minimize the possibility you are using the wrong type. But you of course always have to pay attention.

Wagner R. Landgraf


4. Thursday, March 22, 2018 at 5:48:47 PM

Correct order but not just for that reason. If Unit1 uses Unit2, Unit3 and Unit2 uses Unit3 then they will compile in the order Unit3, Unit2, Unit1 regardless of the order of the uses clauses. What you can guarantee though is that Delphi Units don''t call any non-Delphi units, third party units don''t call yours and your open source code doesn''t call your proprietary code. The four groups will therefore compile in the order specified. If you specified in a different order, they could well still compile in that order. It''s just hard to predict. The individual units may still be in any order within the group so specifying the unit is never a bad idea.

Peter Davies




Add a new comment:
Author:
Email:
  You will receive a confirmation mail with a link to validate your comment, so please use a valid email address.
Comment:
 
Change Image
Fill in the characters from the image above:
 

All fields are required.
 




Previous  |  Next  |  Index