Recent

Author Topic: [SOLVED] How to bundle many units through one unit, possible? Desirable?  (Read 354 times)

BrainChemistry

  • Jr. Member
  • **
  • Posts: 73
Hi everybody, here is a challenge for you! :D

There is a very important principle in Pascal:

Use units to structure the code.

Let's assume you have a library which consists of many units (Base, BaseExt1, BaseExt2,...). Each unit contains one distinct class.

If I want to use this library I have to include all the units in the program file. It would be far more desirable to have just one "library unit" instead which also presents all the functionality of all the other units (their interface parts) to the program.

My first approach:
unit1.pas "forwards" all the functions of the other units.

E.g.
Code: Pascal  [Select][+][-]
  1. unit unit1;
  2. ...
  3. unit2.myfunc: Integer;
  4. ...
 

But this is restricted to functions. Constants and records cannot be forwarded this way (if I remember correctly). Also this means you have to basicly write down the interfaces of all the other units in unit1 again. If you change something in one of these units, you have to update unit1, too. This is no clean way.

My second approach:
Using namespaces: Since FPC 3.0.0 and Delphi 2009 (I guess?) namespaces are supported in the form of dotted units. My understanding was, that if I rename the units to e.g.:

libunit
libunit.base
libunit.ext1
libunit.ext2
...

it would be possible to just put libunit in the uses clause of the program file. This fails though. And on closer examination of the reference link given above, it doesn't seem to be made for that purpose.

Any hints on how to achieve to load all the units (of a library) by just calling the base library unit in the uses clause of the program?

Best regards
BC



« Last Edit: August 04, 2020, 02:52:33 am by BrainChemistry »

Warfley

  • Sr. Member
  • ****
  • Posts: 302
Re: How to bundle many units through one unit, possible? Desirable?
« Reply #1 on: August 03, 2020, 07:15:36 pm »
For types and untyped constants it is very easy:
Code: Pascal  [Select][+][-]
  1. type
  2.   TMyType = OtherUnit.TMyType;
  3.  
  4.  
  5. const
  6.   MyConst = OtherUnit.MyConst;

For functions and typed constants you get into the problem that if the type of the function signature changes you need to change it at two different places.

For variables there is a keyword with which a variable references another variable (aliases or something like that) but I don't remember it exactly and don't know if it works cross units.


But you still have the problem for functions and typed constants and variables, that signature changes require changes at multiple locations. So you have basically two options:
1. don't use multiple units (you can for example simply use include files, this is how it is handled in the RTL in various places)
2. generate your unification unit automatically (simply write a simple generator program using code-tools that scans for everything published in the interface and creates a new unit for this)
3. Only use types

Example for the third point, instead of this:
Code: Pascal  [Select][+][-]
  1. const MyConst: Integer = 10;
  2. procedure MyProcedure;
you can do something like this:
Code: Pascal  [Select][+][-]
  1. TMyWrapper = class
  2. public
  3.   const MyConst: Integer = 10;
  4.   class procedure MyProcedure;
  5. end;
and publish TMyWrapper

BrainChemistry

  • Jr. Member
  • **
  • Posts: 73
Re: How to bundle many units through one unit, possible? Desirable?
« Reply #2 on: August 03, 2020, 10:04:42 pm »
But you still have the problem for functions and typed constants and variables, that signature changes require changes at multiple locations. So you have basically two options:
1. don't use multiple units (you can for example simply use include files, this is how it is handled in the RTL in various places)
2. generate your unification unit automatically (simply write a simple generator program using code-tools that scans for everything published in the interface and creates a new unit for this)
3. Only use types

Thanks for your reply! At least I didn't overlook some obvious solution.

About option 1 (include files): I checked the RTL and found some examples. Thanks for this hint. I guess this is my way to go. Still I wonder, this contradicts the Pascal rule that one should try to keep classes in separate units. Also, the way with the include files has the drawback that I have to include two files for one class: One for the interface, one for the implementation. I hope the code tools of Lazarus IDE can handle this, too.

The other options are nice but kind of overcomplicate the code for me.

(Hint: I keep this question open for further replies or elaboration; will mark it as solved if no further remarks are made. I would be interested though.)

Best regards
BC


Warfley

  • Sr. Member
  • ****
  • Posts: 302
Re: How to bundle many units through one unit, possible? Desirable?
« Reply #3 on: August 03, 2020, 10:13:10 pm »
Lazarus and code tools work fine with include files. The only thing that can be a little bit annoying is auto generation of functions and stuff, because if there is not already other reference functions (i.e. functions of the same class, it might just put it in any of the include files (or none of them). But when it has some reference (like you are adding a function below another one) Lazarus should put the new function right below the other one in the same include file

PascalDragon

  • Hero Member
  • *****
  • Posts: 2103
  • Compiler Developer
Re: How to bundle many units through one unit, possible? Desirable?
« Reply #4 on: August 03, 2020, 10:16:54 pm »
If I want to use this library I have to include all the units in the program file. It would be far more desirable to have just one "library unit" instead which also presents all the functionality of all the other units (their interface parts) to the program.

There is not really any other way except what Warfley already highlighted. I personally don't recommend such techniques, instead you should structure your units nicely, because the following is not a rule:

Still I wonder, this contradicts the Pascal rule that one should try to keep classes in separate units.

The idea of units is instead to keep those types and routines together that belong together and move those shared between units into a third unit.

Also, the way with the include files has the drawback that I have to include two files for one class: One for the interface, one for the implementation. I hope the code tools of Lazarus IDE can handle this, too.

You can put the interface and the implementation part into an include file and protect them with ifdefs and only enable the interface or the implementation part when including the file. There are some units in the FPC repository that do just that.

Please note however that if you decide to use the include file approach that you'll get different types if you have the types in separate units and inside a "all in one" unit whereas if you use type forwarding those will be the same.

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 8719
  • FPC developer.
Re: How to bundle many units through one unit, possible? Desirable?
« Reply #5 on: August 03, 2020, 10:18:21 pm »
  this contradicts the Pascal rule that one should try to keep classes in separate units.

There is no such rule in Pascal afaik. See e.g. a core unit as classes that has many classes in it. Worse, fragmentating sources will only lead to cycles and forward declaration issues.

You may have been thinking of Java.

Dotted unitnames are mostly just that. Calling them namespaces is strictly (maybe) true, but a stretch.

Languages like Java and .NET have totally different mechanisms of searching for source, more modelled after Pascal's successors (like Oberon) than Pascal itself, principles/features don't travel well between them
« Last Edit: August 03, 2020, 10:20:09 pm by marcov »

BrainChemistry

  • Jr. Member
  • **
  • Posts: 73
Re: How to bundle many units through one unit, possible? Desirable?
« Reply #6 on: August 04, 2020, 02:52:18 am »
Thanks everybody for the elaboration! I learned from it!

Case solved for me.  :)

 

TinyPortal © 2005-2018