Marco van de Voort wrote 5 lines
> The definitions of templates, inline procedures or macros do not
> immediately contribute to the size of a compiled module, only when they
> are *used* in code modules.
That goes for all routines.
I'm not sure what you mean. A global procedure, exported in the interface section of a unit, always must be be compiled. Only the linker can determine which procedures really are used in a project, and which ones can be omitted. A specific procedure can be used in one project, but can be unused in another project. Think of the standard units like System...
Show quoted text 5 lines
> In comparison with C/C++, "uses" summarizes the #include of header files
> and the dependency checks of Make.
The important difference (in TP/Delphi/FPC) is that preprocessor state
doesn't follow USES statements.
Do you mean that only one level of dependencies must be checked with "uses", whereas even the indirectly #included files must be checked for changes?
That allows the compiler to auto-find the compilation order..
What's the importance of a compilation order?
Show quoted text 6 lines
> Many properties make Pascal compilers faster than C/C++ compilers. The
> effect of "uses" is equivalent to C/C++ precompiled header files.
The effect of units is that it is a lot safer (more guaranteed) and easier
to implement that precompiled header files, and auto-building is also a lot
easier (not requiring explicit manual compile order enforced)
Again I don't understand what you mean (compile order???) :-(
A C project doesn't require any compilation order, every module can be compiled independently from other modules. The problem is not the order, instead it's the condition, *when* a module has to be recompiled.
Show quoted text 5 lines
> > > The only *disadvantage* of units are the current Pascal compilers, which
> > > cannot handle circular unit references :-(
It could in theory deal with some forms of circular records. Specially in
the case of e.g. classes.
I can imagine some kind of extended "forward" declarations, extending into other units. In most cases it's suffient, for compilation, that the general kind of a named type is known, in detail with pointers and references. Then it's possible to layout records, classes or other structured data types, including parameter lists of subroutines, without the exact knowledge of the referenced types. Knowledge about the exact types usually is required only when members of some referenced complex type come into the play, what does not normally happen in declarations (interface part of units).
Perhaps I should give some examples:
type
A = record a1: B; end;
B = record b1: A; end;
Such a construct of course is illegal, because of infinite recursion. The same construct would be perfectly accepatble with pointers:
type
A = record a1: ^B; end;
B = record b1: ^A; end;
My idea for extended external declarations:
type
C = class in OtherUnit;
or
OtherUnit.C = class;
Now the compiler can insert a reference to OtherUnit.C for every occurence of C in the remainder of the interface section. The OtherUnit now can be moved from the uses list of the interface section into the uses list of the implementation section; or it's imported implicitly, in the most comfortable case.
Just recompile till CRCs don't change anymore. This allows units that
circularly import eachother, but have no real circular dependancy of types
to compile. Or even if the circular reference only involves types of which
the sizes are known (like class etc types that are only 4 bytes).
I would be happy with the latter case and no recompilation at all.
However it is of course questionable if it is worth the trouble to implement
this, and make it bullet proof. Maybe somebody who does graph theory as
a hobby?
I don't qualify as graph theory guru, even if I have already implemented the analysis of control flow graphs in my decompilers. In the case of circular unit references I'd ignore the unit dependencies for themselves, and instead concentrate on the type definitions themselves. There I'd use a list of type names, with some fixed attributes (unit, size, immediate type...), and a reference to the detailed definition of the base type, in case of more complex types. Then the existence of a (illegal) loop can be determined from a Nil reference, whenever access to the detailed definition is actually required. The unit attribute in the fixed part of a type definition is required to distinguish definitions of the same name in different units, and it also can be used to complete forward (or external) type references when the defining unit is imported later.
IIRC TP could handle mild circular references and so can FPC. I don't know
if this is still the case.
Sounds interesting, do you have more information?
DoDi