Jump to content
dmitrybv

F2047 Circular unit reference.

Recommended Posts

Hello 

 

If a project has many classes that are defined in different files, and the classes refer to each other, then at a certain stage a compilation error begins to occur:

 

[dcc32 Fatal Error] EhLib.FMX…….pas(19): F2047 Circular unit reference to 'EhLib.FMX……..'

 

To fix this error, you have to shove all the classes into one file and as a result, the project ends up with one huge file that is not convenient to work with.

 

Who is coping with this problem and how?

Share this post


Link to post

I move my own units from the uses clause in the interface section to the implemenation section. An example would be two forms that access some of each other's properties and objects. They have each other listed in the implementation's uses clause. 

Share this post


Link to post

If in unit1 I move a reference to unit2 to the implementation section, then I cannot use classes from unit2 in the interface section of unit1.

Share this post


Link to post
4 hours ago, dmitrybv said:

Who is coping with this problem and how?

You need to de-couple the classes so they don't refer to each other directly anymore.  Use interfaces or events/callbacks instead.

  • Like 3

Share this post


Link to post
8 hours ago, Remy Lebeau said:

You need to de-couple the classes so they don't refer to each other directly anymore.  Use interfaces or events/callbacks instead.

Interfaces and callbacks might be the solution, but I'm always very sceptical of people who will tell you the solution to a problem that hasn't been clearly stated. 

Share this post


Link to post
Posted (edited)

Beside other tools, I like Uwe Raabes Mmx CodeExplorer and here is another nice tool from Alexander Sviridenkov coping with that.

Generally, like said before, you could consider to move critical references from the "interface uses" to the "implementation uses", wherever necessary,
and to split up classes into interfaces and implementations in separate units.

Edited by Rollo62

Share this post


Link to post
Posted (edited)

Alternate way.  Consider program schema to 'Broker' serving UI by listening to events

  

In FMX you can use TControl where in VCL TWinControl usually needed. Meaning only deal with the components.  The broker or server of Application sits in a Datamodule.  This broker listens for User generated events and updates the Control UI in response. Also the broker updates the UI on timer events.     

 

Using java style to find controls  ClassName 'TStringGrid' vs ClassType(TStringGrid) to find controls to assign the update.  The FMX allows forms considered as TControls where in VCL screen.formname is used to find form needed.          

 

  • Stream in the forms dfm Controls
  • change fixup~to bind the updates
  • Need less timers
  • Uwe's shows one cycle three deep on  a project with 30 forms 
  • Alex's graph works well too.     
Edited by Pat Foley
StringGrid was StringList

Share this post


Link to post

It would be awesome feature request if this problem were solved by the compiler. But I suspect we need to be able to allow forward declarations on all types first (e.g. records), before we can go cross unit. 

 

As mentioned before, if the stuff causing the circular reference is only needed in the implementation, moving the respective unit(s) referencing the respective the dependencies to the implementation may solve the problem.

 

Otherwise, you need to have another unit that either implements the an interface/base class/abstract class dependencies that can then be used by the respective units where the circular issues exist. 

 

In this case, as general abstract strategies, the above techniques have been used to solve this type of problem, without getting into the specifics.

 

20 hours ago, dmitrybv said:

To fix this error, you have to shove all the classes into one file and as a result, the project ends up with one huge file that is not convenient to work with.

I am not so convinced by by this approach, as dmitry identified, it would not be very convenient long term. Some analysis/refactoring is definitely required.

Share this post


Link to post
22 hours ago, darnocian said:

It would be awesome feature request if this problem were solved by the compiler.

I don't think circular references need to be solved by the compiler. In my experience, this has always been a signal that two things which shouldn't be are coupled too tightly and some refactoring is in order.

  • Like 1

Share this post


Link to post

If we compare this feature with other programming languages, then, for example, in C# you can separate the implementation of classes in several files and you can declare references to any public classes and any internal classes in the assembly, regardless of in which files the class is declared.
Perhaps in Delphi we need to introduce such a concept as an assembly or library, within which classes can refer to each other in the interface part.
In general, when developing classes, you want to operate only with such concepts as a library and a class, but you don’t want to think about which file it should be described in so that it can be used in other classes of the library.

Share this post


Link to post

The plethora of working Delphi programs are proof that there already exist concepts to eliminate dependencies between units. They may differ from those available in other programming languages, though.

 

IMHO, circular dependencies should be eliminated even if they appear in implementation sections and thus making the code compile. I wouldn't support any request to extend that in any way leading to more circular dependencies.

  • Like 5

Share this post


Link to post
1 hour ago, dmitrybv said:

If we compare this feature with other programming languages, then, for example, in C# you can separate the implementation of classes in several files and you can declare references to any public classes and any internal classes in the assembly, regardless of in which files the class is declared.
Perhaps in Delphi we need to introduce such a concept as an assembly or library, within which classes can refer to each other in the interface part.
In general, when developing classes, you want to operate only with such concepts as a library and a class, but you don’t want to think about which file it should be described in so that it can be used in other classes of the library.

Nah, it is fine the way it is. Delphi Pascal already provides everything you need to decouple code and even throw partial implementations into myriad units if you really want to. The compiler is already lenient enough for those who are in a rush or don't care to decouple their code, allowing units to require each other to build as long as you keep the interface/implementation dependencies straight. 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×