delphi XE multi-unit namespace question - delphi

I am reading RAD Studio Documentaion in Delphi XE.
here a some texts.
[ Delphi Reference -> Delphi Language Guide -> Programs and Units -> Using Namespaces -> Searching Namespaces -> Multi-unit Namespaces ]
Multi-unit Namespaces
Multiple units can belong to the same namespace, if the unit declarations refer to the same namespace.
For example, one can create two files, unit1.pas and unit2.pas, with the following unit declarations:
// in file 'unit1.pas'
unit MyCompany.ProjectX.ProgramY.Unit1
// in file 'unit2.pas'
unit MyCompany.ProjectX.ProgramY.Unit2
In this example, the namespace MyCompany.ProjectX.ProgramY logically contains all of the interface symbols from unit1.pas and unit2.pas.
Symbol names in a namespace must be unique, across all units in the namespace.
In the example above, it is an error for Unit1 and Unit2 to both define a global interface symbol named mySymbol
I tested this.
code below .
-----------------------------------------------------------------
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils,
Lib.A in 'Lib.A.pas',
Lib.B in 'Lib.B.pas';
begin
WriteLn ( TestValue ) ;
ReadLn ;
end.
-----------------------------------------------------------------
unit Lib.A;
interface
const TestValue : Integer = 10 ;
implementation
end.
-----------------------------------------------------------------
unit Lib.B;
interface
const TestValue : Integer = 10 ;
implementation
end.
This is not error. Why? I don't understand.

Your code does not match the documentation. Documentation explicitly states that file name of 'unit MyCompany.ProjectX.ProgramY.Unit1' is unit1.pas, not MyCompany.ProjectX.ProgramY.Unit1.
I do not believe, however, that this feature is implemented at all. If I change your code to store first unit in file a.pas and second unit in file b.pas, units don't compile at all and the error is
[DCC Error] A.pas(1): E1038 Unit identifier 'Lib.A' does not match file name
(Which is exactly as I was expecting to see.)
In your case there's no conflict because you can always use a full name of 'conflicting' global - Lib.A.TestValue and Lib.B.TestValue.

In Delphi.NET (before Prism): unit name = namespace. That's the way they used it in that time - and in dotNET an unit was really an namespace (inclusive appear as such in generated IL).
In native Delphi, I don't see the difference (if that exists at all).

Related

Delphi 10.2.3: Where is in Delphi the function VarType ()?

I am trying to convert Delphi2005 code to Delphi Tokyo 10.2.3 code.
The function VarType is no longer recognized.
I need the function VarType to determine the basic type of a variant variable. In general I find, according to many postings, that it should be in the unit System.Variants. However, if I search e.g. in:
http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/!!FUNCTIONS_System.html
It is not in this unit. Furthermore, I cannot find the unit variants, only a unit variant.
However, using the unit variant I get a runtime error:
Record, object or class type necessary
. So this doesn't work.
if (System.Variant.VarType(Value) and varTypeMask) =
System.Variant.varString then // VarType(Value) unbekannt
begin
TByte8Array(PRecFORMULA3(PBuf).Value)[0] := 0;
end;
Anyway I don't find VarType in System.variant. Does variants not exist anymore?
Can anyone help me?
The documentation you linked to is quite old. It is for Delphi 2009, which predates the introduction of Unit Scope Names. But even in that old documentation, VarType() is documented as being in the Variants unit (not in the Variant unit, which does not exist).
Unit Scope Names, like System, were added to RTL/VCL unit names in XE2 (thus, the Variants unit became System.Variants).
Embarcadero's newer DocWiki, which replaces the old Docs site, clearly shows that the VarType() function is indeed located in the System.Variants unit.
Make sure that either:
you have System.Variants in your uses clause:
uses
..., System.Variants;
you have System in your project's list of Unit Scope Names, and then you can use Variants in your uses clause:
uses
..., Variants;
Either way, you can then use VarType() as expected, without having to fully qualify it:
if (VarType(Value) and varTypeMask) = varString then
begin
TByte8Array(PRecFORMULA3(PBuf).Value)[0] := 0;
end;

Is it good practice to exploit a compiler bug?

Recently I found some odd-looking (to me) Delphi code and I have isolated it to a separate small project. Here is what I discovered. Unit1 compiles with no errors. Unit2 (which I provide for comparison) does not. The difference is in the way that Classes is used.
unit Unit1;
interface
uses Classes; // difference here
type TThread = class(Classes.TThread)
public
property Terminated;
end;
implementation
end.
Unit2 does not compile. Various errors are produced.
unit Unit2;
interface
uses System.Classes; // difference here
type TThread = class(Classes.TThread)
public
property Terminated;
end;
implementation
end.
[dcc32 Error] Unit1.pas(7): E2003 Undeclared identifier: 'Classes'
[dcc32 Error] Unit1.pas(7): E2029 ',' or ':' expected but ')' found
[dcc32 Error] Unit1.pas(9): E2147 Property 'Terminated' does not exist in base class
So my concern is that this project is exploiting a compiler bug to achieve it's goals. The compiler bug might be fixed in a later release, and then the code won't work anymore.
There is no compiler bug that makes Unit1 compile. It compiles because in the project setting the entry for Unit Scope Names contains at least the item System, which is used to resolve the reference to Classes in the full name System.Classes. As the uses contains Classes, the reference to Classes.TThread also succeeds.
In Unit2 the uses contains System.Classes. Therefore the reference Classes.TThread cannot be resolved anymore. Change it to System.Classes.TThread and it works.
If you uses System.Classes you must also use System.Classes when referring to the classes unit in the code as shown below.
unit Unit2;
interface
uses System.Classes; // difference here
type TThread = class(System.Classes.TThread)
public
property Terminated;
end;
implementation
end.

Why doesn't the Delphi compiler warn for a redefined constant?

A colleague of mine bumped into a constant that had suddenly 'changed value';
Turned out, it was redeclared:
unit Unit1;
interface
const
MyConstant = 1;
implementation
end.
--
unit Unit2;
interface
const
MyConstant = 2;
implementation
end.
--
Uses Unit1, Unit2;
// Uses Unit2, Unit1;
procedure TFrmRedefineConstant.FormShow(Sender: TObject);
begin
ShowMessage('MyConstant: ' + IntToStr(MyConstant));
end;
This shows 2. If you swap the unit order in the Uses statement, it shows 1.
Fine, but why does the Delphi compiler not warn about the duplicate constant name (That would be very helpful)?
Is there anything I can do to enable warnings (does not look that way).
Because of Delphi documented scoping rules. From the Language Guide:
The order in which units appear in the uses clause determines the
order of their initialization and affects the way identifiers are
located by the compiler. If two units declare a variable, constant,
type, procedure, or function with the same name, the compiler uses the
one from the unit listed last in the uses clause. (To access the
identifier from the other unit, you would have to add a qualifier:
UnitName.Identifier.)
This is the expected behaviour since Turbo Pascal 4.0, which introduced units.

What unit scope do I need for this?

I am trying to install a 3rd party package and I get a compile error:
[DCC Error] fiile/line : E2003 Undeclared identifier: 'Windows'
which refers to this line:
wnd := Windows.GetFocus;
It seems fairly obvious that I don't have my Unit Scopes right - but which do I need (and is there a general approach to find which use clause I need)?
I currently have
Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;System;Xml;Data;Datasnap;Web;
Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;Winapi;System.Win
[Update]
interface
uses
SysUtils, winapi.windows, Classes, Controls, ExtCtrls, Graphics, StdCtrls,
Dialogs, IniFiles, winapi.messages, Forms, Math
{$IFDEF DELPHI6_LVL}
, Variants
{$ENDIF}
;
No uses in the impementation section.
[Upate]
I forgot to mention. I failed (in the same way) to install it on one laptop. Then I succeeded on a second. The trouble is that I'd rather have it on my desktop and after a fresh install of XE2 starter I get these problems.
Assuming that your uses names the Windows unit at all, it would appear to do so by naming the unit as Winapi.Windows. And so your code must also do so and be written as
wnd := Winapi.Windows.GetFocus;
When you use a unit by naming the fully scoped unit name, you must also use the fully scoped name in subsequent code in that unit.
Now, if you want to use the name Windows then you must name the unit as Windows in the uses clause and let the unit alias setting do its job. If you imported the unit by naming it Windows then your original code will work.
To be very clear:
uses
Winapi.Windows;
is what you have now but you would need:
uses
Windows;
for your code to compile.
You unit scope looks fine, so try these two options
declare in your uses section Windows instead of Winapi.Windows
or modify your code like so
wnd := Winapi.Windows.GetFocus;

Delphi 7 make complains about files not found

I've got a BPG file that I've modified to use as a make file for our company's automated build server. In order to get it to work I had to change
Uses * Uses
unit1 in 'unit1.pas' * unit1
unit2 in 'unit2.pas' * unit2
... * ...
in the DPR file to get it to work without the compiler giving me some guff about unit1.pas not found.
This is annoying because I want to use a BPG file to actually see the stuff in my project and every time I add a new unit, it auto-jacks that in 'unitx.pas' into my DPR file.
I'm running make -f [then some options], the DPR's that I'm compiling are not in the same directory as the make file, but I'm not certain that this matters. Everything compiles fine as long as the in 'unit1.pas is removed.
It could come from the fact, that the search path in the IDE and the search path of the command line compiler are not the same. If you change the serach path of the command line compiler you might be able to use the exactely same source code as within the IDE.
One possibility to configure the search path for the command-line compiler is to do it in a file called dcc32.cfg. Take a look at the help, there is a short description of dcc32.cfg in the IDE-help.
Well this work-around worked for me.
//{$define PACKAGE}
{$ifdef PACKAGE}
uses
unit1 in 'unit1.pas'
unit2 in 'unit2.pas'
...
{$else}
uses
unit1
unit2
...
{$endif}
The only problem is whenever you add a new unit, delphi erases your ifdef package at the top.
Every time I have to put conditionals into a project file I do this:
program a;
uses
ACondUnits;
...
unit ACondUnits;
interface
uses
{$IFDEF UseD7MM}
Delphi7MM;
{$ELSE}
FastMM4;
{$ENDIF}
implementation
end.
Maybe this trick works in packages too. Never tried.

Resources