1
votes

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

3

3 Answers

5
votes

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.

0
votes

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.

0
votes

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;