views:

516

answers:

5

When using Delphi: If I have a unit that is filled with constants like...

Unit AConsts;
Interface
Const
     Const1 : WideString = 'Const1';
     Const2 : WideString = 'Const2';
     Const3 : WideString = 'Const3';
     Const4 = 100;
     Const5 = 100;
Implementation
end.

and I want to use this unit from another unit, is there any difference between...

Unit AUnit;
Interface
Uses 
    AConsts;
Implementation
end.

and

Unit AUnit;
Interface
Implementation
Uses
    AConsts;
end.

? Or in other words, is there a difference between the two as far as a compiled app is concern?

[Edit 1]

Thanks for the answers so far.

I didn't make this question clear enough, and for that I apologise. The question is not about scope, avoiding circular references etc. It is about differences in the compiled app. Maybe another example would help.

If UnitA, UnitB and UnitC all use AConsts, would there be a difference in the compiled app (assuming no name clashes between the constants in the AConsts units and other code) between App1 where these UnitA, UnitB and UnitC all have AConsts in the Interface section's uses clause and App2 where UnitA, UnitB and UnitC all have AConsts in the Implementation section's uses clause.

+1  A: 

Items in the uses statement in the interface are visible in the entire unit.

Items in the uses statement in the implementation are only visible in the implemantation section.

Example:

unit A;
interface
const 
  cA = 1;
..


unit B;
interface
const 
  cB = 1;
..



unit C;
interface
uses
  A;
const 
  cC1 = cA;
  cC2 = cB; // Error

implementation
uses
  B;
const
  cC3 = cA;
  cC4 = cB;

end.

You can create mutual dependent units if at least one unit is included in the implementation section:

unit A;
interface
implementation
uses
  B;
end.


unit B;
interface
implementation
uses
  A;
end.

If both are used in the interface section it won't compile/link.

Gamecat
+7  A: 

The difference has to do with where you're allowed to refer to the things that AConsts has in its interface section. In the first AUnit, you could use Const4 to declare a fixed-size array in that interface section. You couldn't do that in the second AUnit because Const4 isn't in scope.

It can have an effect on the compiled program, if you're not careful. Suppose we have another unit that also declares a constant named Const4:

unit BConsts;
interface
const
  Const4 = 50;
implementation
end.

Now we define an array in UnitA like this:

unit AUnit
interface
uses BConsts;
var
  data: array[0..Pred(Const4)] of Integer;
implementation
uses AConsts;
procedure Work;
var
  i: Integer;
begin
  for i := 0 to Const4 - 1 do begin
    data[i] := 8;
  end;
end;
end.

That code will write beyond the end of the array because the Const4 that's in scope in the interface section is not the same Const4 that's used in the implementation section. This doesn't happen often with constants. It usually just happens with two identifiers, the FindClose function defined in Windows and SysUtils, and TBitmap, defined in Graphics and Windows. And in those two cases, the compiler will tell you that you've done something wrong, although it won't tell you precisely that you've used an identifier that has two different meanings. You can resolve the problem by qualifying the identifier:

for i := 0 to BConsts.Const4 - 1 do
  data[i] := 8;

If all the above precautions are addressed, so your program compiles and runs correctly, then it makes no difference where units are used. In your example with App1 and App2, the two programs will be the same. They won't be identical — the compiler will have processed things in a different order and thus will likely put things in different places — but it will have no effect on the execution of your program.

Rob Kennedy
+2  A: 

The IDE also uses how where you declare your uses to ascertain what it needs to compile.

If your interface section uses UnitA and your implementation section uses UnitB then, if unit B needs recompiling, your unit won't, but if unitA changes then your unit will need to be recompiled.

It's one of the secrets of Delphis super fast build speed.

As to your finished executable, I expect that it will turn out the same size wherever you put the declarations (the linker is clever and only links in methods etc that are actually used by your application), but the actual location of various sources would almost certainly change if the order of the unit declarations is changed.

Mike Sutton
+1  A: 

I follow a rule that I put everything on Interface part unless I need to deal with problems with circular references. This helps to bring a little clarity. Some wizards in Delphi and "File>Use Unit..." dialog put units on implementation section.

Except for the scoping traps which Rob Kennedy highlighted, it's doesn't matter. Make your standard and stick with it.

Fabricio Araujo
+1  A: 

I put all references in the implementation section and only put those unit names in the interface that I have to.

I like to limit the scope of everything as much as possible, though, and this policy is pursuant to that.

Nick Hodges