Reputation: 5158
I use Bold for Delphi as ORM framework and I try to write how the codegeneretion works to better understand my question. A model stored in a bld-file is used as source for generating the class definitions for classes in the model.
So a file called BusinessClasses.pas is generated from scratch. Structure is like this:
unit BusinessClasses;
{$DEFINE BusinessClasses_unitheader}
{$INCLUDE BusinessClasses_Interface.inc}
{$INCLUDE AmObject.inc}
{$INCLUDE Quantity.inc}
{$INCLUDE Distance.inc}
// etc. My source have about 80 inc-files with code
const
BoldMemberAssertInvalidObjectType: string = 'Object of singlelink (%s.%s) is of wrong type (is %s, should be %s)';
{ TBusinessClassesRoot
All classes in model inherit from TBusinessClassesRoot.
Following is base methods that can be used everywhere}
procedure TBusinessClassesRootList.Add(NewObject: TBusinessClassesRoot);
begin
if Assigned(NewObject) then
AddElement(NewObject);
end;
function TBusinessClassesRootList.IndexOf(anObject: TBusinessClassesRoot): Integer;
begin
result := IndexOfElement(anObject);
end;
function TVehicle._GetRegNo: String;
begin
Result := M_RegNo.AsString;
end;
procedure TVehicle._SetRegNo(const NewValue: String);
begin
M_RegNo.AsString := NewValue;
end;
// So all basic methods that Get and Set attributes for all classes is here.
// In my case it means a big file about 83000 LOC.
Code in BusinessClasses_Interface.inc look like this:
{$IFNDEF BusinessClasses_Interface.inc}
{$DEFINE BusinessClasses_Interface.inc}
{$IFNDEF BusinessClasses_unitheader}
unit BusinessClasses;
{$ENDIF}
interface
uses
// interface uses
{$INCLUDE Attracs_Interface_Uses.inc} ,
// other
Classes,
// more uses follow...
type
{ forward declarations of all classes }
TBusinessClassesRoot = class;
TBusinessClassesRootList = class;
TaccountProperty_TransportAccountProperty = class;
TaccountProperty_TransportAccountPropertyList = class;
// A lot of forward declarations follow....
TBusinessClassesRoot = class(TBoldObject)
private
protected
public
end;
TaccountProperty_TransportAccountProperty = class(TBusinessClassesRoot)
private
function _GetaccountProperty: TTransportAccountProperty;
function _Get_M_accountProperty: TBoldObjectReference;
protected
public
property M_accountProperty: TBoldObjectReference read _Get_M_accountProperty;
property accountProperty: TTransportAccountProperty read _GetaccountProperty;
end;
// More class declarations follow
// File size is about 35000 LOC
So BusinessClasses_Interface.inc and BusinessClasses.pas is generated from scratch while the inc-files like AmObject.inc with real code is maintained by the developer.
It have been worked like this all the time since D7. But there are some disadvantages.
So my initial idea was to convert all inc-files to standard pas-files instead. The reference to code should go by uses instead of $INCLUDE inc-file. Then I discovered why this odd solution to store code in inc-files was chosen. Two classes in the model can be interlinked. It means that Class A have a reference to Class B. And Class B have reference to Class A. This must work. Class forward declarations is used for that. And Delphi compiler seems to require this.
A forward declaration must be resolved by a defining declaration of the same class within the same type declaration section. In other words, between a forward declaration and its defining declaration, nothing can occur except other type declarations.
So Delphi 10.3 Rio works exactly the same as in old D7.
Ok, so now at last my question :)
I have not seen any other projects than Bold to use inc-files to store code. Is there any other trick or solution to achieve the same result ?
Upvotes: 0
Views: 1395
Reputation: 5158
I now believe I have a solution to the problem. I think the culprit is that classes have direct access to each other. So class A is aware of class B etc. So interfaces could be the solution.
Unfortunately it means a lot of work in my case as all references in model need to be changed. Also codegeneration need generate interfaces instead of direct links.But the most work required would being Bold framework itself as it don't support interfaces now.
But this small sample works at least:
Unit A
unit TestA;
interface
uses
TestInterfaces;
type
TTestA = class
M_TestB: ITestB;
end;
implementation
end.
Unit B
unit TestB;
interface
uses
TestInterfaces;
type
TTestB = class
M_TestA: ITestA;
end;
implementation
end.
interfaces
unit TestInterfaces;
interface
type
ITestA = interface
['{5DE20444-241E-4F59-9B7F-96A76BA3DDFF}']
end;
ITestB = interface
['{40C19A93-C816-4D1E-9C74-6B710D6974BF}']
end;
implementation
end.
Upvotes: 0
Reputation: 2043
The simplest solution would be to run a pascal preprocessor after generating the include and unit files to merge the include files into the unit. Here is one: http://clootie.narod.ru/delphi/download_utils.html#ppp
So all include files will end up inside the unit. The include files can be deleted to avoid confusion.
Upvotes: 1