I have a couple of newbie questions that I cannot seem to find the answers to.
Variables
I have noticed that in some apps they declare variables in the private or public sections of the form type however in other apps they declare them in the implementation part of the form, is there a reason for this or is it just user choice?
Procedures / Functions
Again I have noticed that in some apps procedures / Functions are Declared in the private / public part of the form type and then when created they are prefixed by the form name EG
Procedure Tform1.testproc;
Begin
Blah
End;
Whereas in other apps they are not declared in the form type and are not prefixed with the form name, is there a reason for this? Also which is the best way?
Using other units
Is there a reason why some apps add other units normally user created to a uses clause after the form implementation section whereas other apps add them to the uses clause # the top of the form unit?
Any help / answers to the above questions would be great
Many thanks
Colin
It all depends on visibility.
Types, variables, constants, procedures, and functions declared in the interface section of a unit (but outside of classes and other type definitions) are visible to other units, whereas types, variables, constants, procedures, and functions declared in the implementation section of a unit can only be used in the very same unit (and only below the declaration). Hence, if you need types/variables/functions/... in a particular unit but do not expect the identifiers to make sense outside the unit, then it is a good idea to declare them right before they are needed, in the implementation section.
Further, when it comes to classes, their identifiers can be declared as private, strict private, public, protected, and published. This is again due to different kinds of visibility. Private identifiers can only be used inside the class itself (or other classes defined in the same unit, unless strict private), and so on.
Also, notice this:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
private
{ Private declarations }
alpha: integer;
public
{ Public declarations }
end;
var
Form1: TForm1;
var
beta: integer;
implementation
{$R *.dfm}
end.
Since alpha is a member of the class TForm1, every instance of this class, that is, every object of this form (that is, every form created of this class) will have its own alpha variable. On the other hand, beta, being declared in the unit outside of any class, is "one per unit", that is, every TForm1 object will see the same beta. (And then there are "class variables" and such. Please see the documentation for more details.)
(Also, you probably already know this, but in a case like
unit Unit3;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm3 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form3: TForm3;
implementation
{$R *.dfm}
procedure TForm3.FormCreate(Sender: TObject);
begin
beep;
end;
end.
you do not have two functions named FormCreate, but only one. The first reference to this function is the declaration, which is part of the class declaration in the interface section, which is what other classes and units will see. The actual implementation of the FormCreate function (or its definition) is always in the implementation section. Indeed, other classes or units do not need to know the exact implementation of the functions in a particular class.)
Finally, I would like to recommend the official Delphi documentation, which is very good. Start at http://docwiki.embarcadero.com/RADStudio/en/Delphi_Language_Guide_Index.
Variables/procedures/functions
It all comes down to where the information is supposed to go.
If it's a method or variable specific to the instance of the form, then you have to declare it in the form type itself. If it applies to all instances of the form, then you put it in the implementation section which makes it global - it's not part of the type.
In many cases, you won't ever have more than a single instance of a single form at a time, so in that case, it generally doesn't matter where you put it, as far as the functionality is concerned - but it's considered good practice to put what you can in the form type, rather than in the implementation section. This is because it keeps the information associated with the form itself, instead of relying on global information which can basically be accessed from anywhere.
Uses
There are two different places to put the uses clause, and you've noticed both of them.
The reason this is needed is because the Delphi compiler is implemented as a single-pass compiler. This makes it fast, but it also means that you have to declare everything in advance, so it knows what to expect.
When using the uses clause after the implementation keyword, the unit is not read until after all of your types are declared. This allows you to have units refer to each other, i.e. Unit1 referring to Unit2 and Unit2 referring to Unit1, because all of the required definitions will be available before a dependency on the other is introduced. This is not possible if both refer to each other from their "top" uses clause.
Since you can be certain that the VCL units won't be referring to any of the units you have in your code, they are therefore safe to include at the top. The same cannot necessarily be said about units you create in your project, so it's safer to add them to the other uses clause.
It's all about Delphi's module system (modules are called units here).
When you declare something inside Interface part of the unit, it is visible to all other units.
Whereas Implementation is visible only for this unit.
And when dealing with classes, private / public relates only to members of this particular class.
Consider:
unit A
//------------------------------------------------
Interface
uses ... // modules on which *iterface* depends
// don't include here modules needed for implementation only
//------------------------------------------------
var visibleVar: Integer; // visible from other units
//------------------------------------------------
type VisibleType = class
public:
visibleMember: Integer; // visible from other units and classes
private:
invisibleMember: Integer; // invisible from other units, but
// visible to other classes in this unit
strict private:
reallyInvisible: Integer; // visible *only* inside this class
end;
//------------------------------------------------
//------------------------------------------------
//------------------------------------------------
Implementation
uses ... // modules on which *implementation* depends (and interface is *not*)
//------------------------------------------------
var invisibleVar: Integer; // can't reference to this from other units
//------------------------------------------------
type InvisibleType = class // can be referenced only from inside this module
public:
modulePrivateMember: Integer; // visible only inside module's implementation
private:
invisibleMember: Integer; // in *this context* essentially the same as "public"
strict private:
reallyInvisible: Integer; // same as in interface - it's just private
end;
Related
In previous versions of Delphi, my custom Form showed its published properties.
However, I'm running into an issue with Delphi 10.2 Tokyo. Specifically, I'm not seeing a good way to call the appropriate method found in this post.
To sum it up, a call to RegisterCustomModule() is needed, however, in the DesignIntf unit described here, there is no TCustomModule (there is TBaseCustomModule and TCustomModuleClass, though), also the base custom module inherits from TInterfacedObject, which TForm does not (using FMX as my framework).
What is the correct method for registering a FMX Form to show published properties in the latest version of Delphi?
uses DesignEditors;
type
TMySpecialForm = class(TCustomForm)
end;
RegisterCustomModule(TMySpecialForm, TCustomModule);
RegisterCustomModule takes 2 parameters: ComponentBaseClass and CustomModuleClass. The first is your custom form class, which will, of course, be derived from TCustomForm. The second is a class that will be used by the designer. This class must do 2 things: derive from TBaseCustomModule (in DesignIntf unit) and implement the ICustomModule interface. Take a look at the comment in the DesignEditors unit, around line 502.
The TCustomModule class is provided for you to use if you have no behavior other than the default to add to your custom form at design time.
If you do want some kind of custom behavior for your form while in the designer, say, a pop-up menu with various property-setting commands, you would create your own TCustomModule class:
uses DesignEditors;
type
TMySpecialFormDesigner = class(TCustomModule, ICustomModule)
function GetVerb(Index: Integer): string; override;
function GetVerbCount: Integer; override;
end;
RegisterCustomModule(TMySpecialForm, TMySpecialFormDesigner);
This Embarcadero article discussing memory issues for the XE7 IDE contains the following:
Be aware of the “Growth by Generics”
Another scenario that might depend on your application code and cause an increase of the memory used by the compiler and the debugger relates with the way generic data types are used. The way the Object Pascal compiler works can cause the generation of many different types based on the same generic definition, at times even totally identical types that are compiled in different modules. While we won’t certainly suggest removing generics, quite the contrary, there are a few options to consider:
Try to avoid circular unit references for units defining core generic types
Define and use the same concrete type definitions when possible
If possible, refactor generics to share code in base classes, from which a generic class inherits
The last item I understand. The first two I am less clear on.
Do these issues affect only IDE performance, or is there an impact on the size of the compiled code?
For instance, considering the second item, if I declare TList<Integer> in two separate units, will I get two separate chunks of code in each of those units in my executable? I certainly hope not!
Point 2. This refers to instantiating same generic type where possible. For instance using TList<Integer> in all places instead of having two generic types TList<Integer> and TList<SmallInt>.
Declaring and using TList<Integer> in several units will only include single copy of TList<Integer> in exe file. Also, declaring TIntegerList = TList<Integer> will result with same.
Generic bloat people are referring to relates to having complete TList<T> copy for each specific type you use even though underlying generated code is the same.
For instance: TList<TObject> and TList<TPersistent> will include two separate copies of TList<T> even though generated code could be folded to single one.
That moves us to Point 3. where using base class for common class code and then using generic classes on top of that to get type safety, can save you memory both during compilation and in exe file.
For example, building generic class on top of non generic TObjectList will only include thin generic layer for each specific type instead of complete TObjectList functionality. Reported as QC 108966
TXObjectList<T: class, constructor> = class(TObjectList)
protected
function GetItem(index: Integer): T;
procedure SetItem(index: Integer; const Value: T);
public
function Add: T;
property Items[index: Integer]: T read GetItem write SetItem; default;
end;
function TXObjectList<T>.GetItem(index: Integer): T;
begin
Result := T( inherited GetItem(index));
end;
procedure TXObjectList<T>.SetItem(index: Integer; const Value: T);
begin
inherited SetItem(index, Value);
end;
function TXObjectList<T>.Add: T;
begin
Result := T.Create;
inherited Add(Result);
end;
The code bloat they are talking about in the article (as it is about the out of memory issue in the IDE) is related to the generated DCUs and all the meta information that is held in the IDE. Every DCU contains all the used generics. Only when compiling your binary the linker will remove duplicates.
That means if you have Unit1.pas and Unit2.pas and both are using TList<Integer> both Unit1.dcu and Unit2.dcu have the binary code for TList<Integer> compiled in.
If you declare TIntegerList = TList<Integer> in Unit3 and use that in Unit1 and Unit2 you might think this would only include the compiled TList<Integer> in Unit3.dcu but not in the other two. But unfortunately that is not the case.
I get an error :
[DCC Error] Unit_TProcessClass.pas(334): E2010 Incompatible Type: 'TBitmap' and 'tagBITMAP'
the class is defined as
TMyClass = Class
private
MyBMP : TBitmap;
property aBMP : TBitmap read MyBMP write MyBMP;
and the code goes like
processABitmap(aMyClass.aBMP) ; -> here is the compile error !!!
The problem is that there are two types named TBitmap in the VCL. One defined in the Windows unit and one defined in Graphics unit. Clearly you are passing Windows.TBitmap to a function expecting Graphics.TBitmap, or vice versa.
You almost certainly don't want to have anything to do with Windows.TBitmap. So the solution is to make sure that all of your units list the Graphics unit after the Windows unit in the uses clause. This will have the effect of hiding Windows.TBitmap.
My psychic debugging suggests that the unit in which TMyClass is declared either does not list Graphics at all in its uses clause, or it lists Graphics before Windows.
Finally, how would you go about working out something like this yourself? Well, try pressing CTRL+click on the TBitmap referenced in TMyClass. I'm confident that they will take you to the TBitmap declared in Windows. That should be enough for you to work out that it's not the type that you meant when you wrote TBitmap.
The problem is that you confuse Windows.TBitmap (aka tagBitmap, a record describing a bitmap in the sense of the Windows API) with Graphics.TBitmap, the VCL bitmap class.
So, you either want
var
b: Windows.TBitmap;
or (much more likely)
var
b: Graphics.TBitmap;
If you omit the unit, then the last-referenced unit will be used. For instance, if your uses clause looks like
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
then TBitmap means Graphics.TBitmap, and this is what you usually want.
So the solution to your problem either is that you need to add Graphics to some uses clause, or that you need to make sure that Graphics is listed after Windows in the list.
This question already has answers here:
Delphi Enterprise: how can I apply the Visitor Pattern without circular references?
(4 answers)
Closed 8 years ago.
Is there a way of getting around circular unit references in Delphi?
Maybe a newer version of delphi or some magic hack or something?
My delphi project has 100 000+ lines of code mostly based on singleton classes. I need to refactor this, but that would mean several months of "circular reference" hell :)
I've been maintaining close to a million lines of legacy code for the past 10 years so I understand your pain!
In the code that I maintain, when I've encountered circular uses, I frequently have found that they are caused by constants or type definitions in unit A that are needed by unit B. (Sometimes it's also a small bit of code (or even, global variables) in Unit A that is also needed by unit B.
In this situation (when I'm lucky!) I can carefully extract those parts of the code into a new unit C that contains the constants, type definitions, and shared code. Then units A and B use unit C.
I post the above with some hesitance because I'm not an expert on software design and realize there are many others here who are far more knowledgeable than I am. Hopefully, though, my experience will be of some use to you.
It seems you have quite serious code design issues. Besides many signs of such issues, one is the circular unit reference. But as you said: you cannot refactor all the code.
Move all what is possible to the implementation section. They are allowed to have circular references.
To simplify this task you can use 3rd party tools. I would recommend
Peganza Pascal Analyzer - it will suggest what you can move to the implementation section. And will give you many more hints to improve your code quality.
Use the implementation section uses whenever possible, and limit what's in the interface uses clause to what has to be visible in the interface declarations.
There is no "magic hack". Circular references would cause an endless loop for the compiler (unit A requires compiling unit B which requires compiling unit A which requires compiling unit B, etc.).
If you have a specific instance where you think you cannot avoid circular references, edit your post and provide the code; I'm sure someone here can help you figure out how to get it fixed.
There is many ways to avoid circular references.
Delegates.
Way too often, an object will execute some code that should be done in an event instead than being done by the object itself. Whether it is because the programmer working on the project was too short on time(aren't we always?), didn't have enough experience/knowledge or was just lazy, some code like this eventually end up in applications. Real world exemple : TCPSocket component that directly update some visual component on the application's MainForm instead of having the main form register a "OnTCPActivity" procedure on the component.
Abstract Classes/Interfaces. Using either of them allow to remove a direct dependance between many units. An abstract class or an interface can be declared alone in its own unit, limiting dependancies to a maximum. Exemple: Our application has a debug form. It has uses on pretty much the whole application as it displays information from various area of the application. Even worse, every form that allows to show the debug form will also also end up requiring all the units from the debug form. A better approach would be to have a debug form which is essentially empty, but that has the capacity to register "DebugFrames".
TDebugFrm.RegisterDebugFrame(Frame : TDebugFrame);
That way, the TDebugFrm has no dependancies of its own (Except than on the TDebugFrame class). Any and all unit that requires to show the debug form can do so without risking to add too many dependancies either.
There are many other exemple... I bet it could fill a book of its own. Designing a clean class hierarchy in a time efficient fashion is pretty hard to do and it comes with experience. Knowing the tools available to achieve it and how to use them is the 1st step to achieve it. But to answer your question... There is no 1-size-fit-all answer to your question, it's always to be taken on a case by case basis.
Similar Question: Delphi Enterprise: how can I apply the Visitor Pattern without circular references?
The solution presented by Uwe Raabe uses interfaces to resolve the circular dependency.
Modelmaker Code Explorer has a really nice wizard for listing all the uses, including cycles.
It requires that your project compiles.
I agree with the other posters that it is a design issue.
You should carefully look at your design, and remove unused units.
At DelphiLive'09, I did a session titled Smarter code with Databases and data aware controls which contains quite few tips on good design (not limited to DB apps).
--jeroen
I found a solution that doesn't need the use of Interfaces but may not resolve every issues of the circular reference.
I have two classes in two units: TMap and TTile.
TMap contains a map and display it using isometric tiles (TTile).
I wanted to have a pointer in TTile to point back on the map. Map is a class property of TTile.
Class Var FoMap: TObject;
Normaly, you will need to declare each corresponding unit in the other unit... and get the circular reference.
Here, how I get around it.
In TTile, I declare map to be a TObject and move Map unit in the Uses clause of the Implementation section.
That way I can use map but need to cast it each time to TMap to access its properties.
Can I do better? If I could use a getter function to type cast it. But I will need to move Uses Map in the Interface section.... So, back to square one.
In the Implementation section, I did declare a getter function that is not part of my class. A Simple function.
Implementation
Uses Map;
Function Map: TMap;
Begin
Result := TMap(TTile.Map);
End;
Cool, I thought. Now, every time I need to call a property of my Map, I just use Map.MyProperty.
Ouch! Did compile! :) Did not work the expected way. The compiler use the Map property of TTile and not my function.
So, I rename my function to aMap. But my Muse spoke to me. NOOOOO! Rename the Class Property to aMap... Now I can use Map the way I intented it.
Map.Size; This call my little function, who typecast aMap as TMap;
Patrick Forest
I gave a previous answer but after some thinking and scratching I found a better way to solve the circular reference problem. Here my first unit who need a pointer on an object TB define in unit B.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, b, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
FoB: TB;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
FoB := TB.Create(Self);
showmessage(FoB.owner.name);
end;
end.
Here the code of the Unit B where TB has a pointer on TForm1.
unit B;
interface
Uses
dialogs, Forms;
type
TForm1 = class(TForm);
TB = class
private
FaOwner: TForm1;
public
constructor Create(aOwner: TForm);
property owner: TForm1 read FaOwner;
end;
implementation
uses unit1;
Constructor TB.create(aOwner: TForm);
Begin
FaOwner := TForm1(aOwner);
FaOwner.Left := 500;
End;//Constructor
end.
And here why it compiles. First Unit B declare the use of Unit1 in the implementation section. Resolving immediately the circular reference unit between Unit1 et Unit B.
But to allow Delphi to compile, I need to give him something to chew on the declaration of FaOwner: TForm1. So, I add stub class name TForm1 who match the declaration of TForm1 in Unit1.
Next, when come the time to call the constructor, TForm1 is able to pass itself has the parameter. In the constructor code, I need to typecast the aOwner parameter to Unit1.TForm1. And voilà, FaOwner his set to point on my form.
Now, if the class TB need to use FaOwner internally, I don't need to typecast it every time
to Unit1.TForm1 because both declaration are the same. Note that you could set the declaration of to constructor to
Constructor TB.create(aOwner: TForm1);
but when TForm1 will call the constructor and pass itself has a parameter, you will need to typecast it has b.TForm1. Otherwise Delphi will throw an error telling that both TForm1 are not compatible. So each time you call the TB.constructor you will need to typecast to the appropriate TForm1. The first solution, using a common ancestor, his better. Write the typecast once and forget it.
After I posted it, I realized that I made a mistake telling that both TForm1 were identical. They are not Unit1.TForm1 has components and methods that are unknown to B.TForm1. Has long TB doesn't need to use them or just need to use the commonality given by TForm you're okay. If you need to call something particular to UNit1.TForm1 from TB, you will need to typecast it to Unit1.TForm1.
I try it and test it with Delphi 2010 and it compiled and worked.
Hope it will help and spare you some headache.
I have a console application written in Delphi.
I saw that I can have global variables by assigning them to unit scopes, but in a console application I don't use units (from what I've understood it's forms-only).
Nope, a unit is not equivalent to a form.
A unit is a module which contains part of your program. Each form is a separate unit but a unit does not have to contain a form.
Each unit has an interface section and a implementation section. The declarations in the interface section are visible to all units that use the unit:
unit A;
interface
type
TMyClass = class
end;
implementation
end.
unit B;
interface
uses
A; // I can now see and use TMyClass.
You can declare global variables by declaring them in a unit:
unit A;
interface
var
GVar1 : Integer;
implementation
var
GVar2 : Integer;
end.
GVar1 is visible and can be modified by all units using unit A. GVar2 is only visisble by the code of unit A because it is defined in the implementation section.
I strongly advice against using globals in the interface section because you have no control over them (because anybody can change them). If you really need a global, you better define it in the implementations section and provide access functions.
By the way, you can see a unit as a kind of a class (with a single instance). It even has a way to construct and destruct:
unit A;
interface
type
TMyClass = class
end;
implementation
initialization
// Initialize the unit
finalization
// Free resources etc. You can olny have a finalization if you have an initialization.
end.
If you want global variable declare it in interface section of your unit.
PS Console aplication can use units.
PPS Take some time and read Delphi documentation, it explains Delphi language pretty well.