[fpc-devel] "Friend" classes?

DrDiettrich drdiettrich at compuserve.de
Sun Mar 27 19:08:34 CEST 2005

Marco van de Voort wrote:

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

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

> That allows the compiler to auto-find the compilation order..

What's the importance of a compilation order?

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

> > > > 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:

  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:

  A = record a1: ^B; end;
  B = record b1: ^A; end;

My idea for extended external declarations:

  C = class in OtherUnit;
  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?


More information about the fpc-devel mailing list