[fpc-devel] Circular references and forward declarations

Juha Manninen juha.manninen at phnet.fi
Tue Jan 5 17:07:43 CET 2010


Hello.

My proposal:
Please allow a forward declaration of a class which is defined in another 
unit, maybe using a new syntax for the declaration.
Alternatively, allow circular references just like other programming languages 
do.

Forbidden circular references is a major annoyance in Object Pascal and one of 
the main (!) reasons why it is not popular for big projects.
I remember comments from other programmers like: "Delphi is not suitable for 
serious SW projects because the source files can't reference each other and 
you must put everything into one big file."
Then I was arguing that no, it is not true, there are ways to go around it. 
Later I did some "serious SW projects" with Delphi and changed my mind.

The problem is about referencing classes between units. Say you have unit 
MyUnit defining class TMyClass. In a typical circular reference situation you 
must define a variable MyVar as TObject (although it's actually TMyClass) and 
then cast it in the implementation section as TMyClass(MyVar).
Very clumsy! And worse, you can't use the nice code completion features of 
your IDE when the variable is defined as "TObject".

One suggestion has been to create an abstract base class into a separate unit 
and reference that in both the inherited class's unit and in the dependent 
unit. Well, I tried that.
First, it creates a completely useless unit, making the code harder to 
understand.
Second, it didn't solve the problem. In REAL programming situations I 
sometimes had to refer to data members in the inherited class (not included in 
the abstract base class to avoid circular reference). Then I again had to cast 
the variable which effectively nullified the whole effort. I could have used 
the "TObject method" as well.

Finally I gave up and copy-pasted everything into one big unit. That's 
apparently what all "serious" Object Pascal projects must do. Virtual TreeView 
is one big file. Lazarus has units of almost 20 000 lines. It is really too 
much. Or, it would be ok if the programmer really wanted to do so but the 
compiler should not force it!

Think of this:
Forward declaration of a class is allowed inside a unit. There can be a 
reference to a class before it is defined! Like:
  TMyClass = class;

Why is it not allowed from another unit? They are conceptually the same thing!
The problem could be solved easily if there was a forward declaration saying:
  TMyClass = class; defined in "MyUnit.pas"
or 
  TMyClass = class; defined outside
or whatever...
That would not create a circular reference error because MyUnit would not be 
in uses clause. IMO, simply allowing circular reference would be the easiest 
solution but maybe it creates some technical problem which I don't know 
about... Well, most other languages can do it...

Many people asked about circular reference in Delphi mailing lists. The 
answers were basically like: "This is the way it is defined and it will not 
change."
Most programmers have switched to some other programming language.
What a surprise!

If I create a feature request issue for this, does it have any chance of being 
implemented? I think it would be EASY to implement. Some other features like 
generics and closures (anonymous functions) need much more effort.


Yours,
Juha Manninen



More information about the fpc-devel mailing list