Jump to content
Ian Branch

Uses units qualifiers?

Recommended Posts

In which version of Delphi were the uses unit's qualifiers like Vcl. & System. introduced?

Share this post


Link to post
8 minutes ago, Ian Branch said:

In which version of Delphi were the uses unit's qualifiers like Vcl. & System. introduced?

Delphi 2005

  • Like 1

Share this post


Link to post

Tks Dave.  I didn't realise it was that 'long' ago.  ;-)

Cheers.

Share this post


Link to post
Posted (edited)
2 hours ago, Ian Branch said:
In which version of Delphi were the uses unit's qualifiers like Vcl. & System. introduced?

They are called Unit Scope Names, not qualifiers.  And don't confuse them with Namespaces, which uses a similar naming syntax but different semantics.

 

Here is a useful site: List of Delphi Pascal Features and When Introduced

Edited by Remy Lebeau
  • Like 1

Share this post


Link to post
2 minutes ago, Remy Lebeau said:

And don't confuse them with Namespaces,

Perish the thought.  🙂

3 minutes ago, Remy Lebeau said:

Here is a useful site:

Excellent.  Tks.

Share this post


Link to post

Actually, the concept of namespaces was introduced with Delphi 2005, but the RTL and VCL started using them much later. A quick search in my installations found vcl.controls.pas appearing in Delphi XE2, before that it was just controls.pas

Share this post


Link to post

Usually I try to use fully qualified namespaces only, in the unit and uses definitions.
Still I can see that many code may use "partly" or "mixed" qualified namespaces, like this:
 

unit MyCompany.Libs.MyUnit1
uses System.Classes,          // Fully qualified name.
     SysUtils,                // Generic name.
     MyCompany.Libs.Unit2,    // Fully qualified name.
     UnitX;                   // Generic name.
      

Are there any insights how this behaves, will the resolver of namespaces work on each single name separately and make a separate decision,
or will the whole "uses" switched into a different, generic mode?

The fully qualified name should be the most performant, and the total generic name should be the least performant, IMHO.
What about a mixture of that, is it exactly according to the number of generic name count in those uses, or does it behave worse than that, more like if all where generic names?


 

 

Share this post


Link to post

 

1 hour ago, Rollo62 said:

Still I can see that many code may use "partly" or "mixed" qualified namespaces,

In XE2 and later, for reasons of backward compatibility I guess, you can get away with not using fully qualified unit scope names for the RTL/VCL etc if you add the required prefixes to project options (Delphi Compiler section, Unit scope names field). Certain default prefixes are added by Delphi when you create a new project. For a new VCL application in Delphi 12.2 I get:

 

Winapi;System.Win;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

 

That's probably why the "mixed" code works, but it's asking for trouble IMHO.

 

I worry about possible conflicts using default unit scope names, so I usually delete all the default prefixes from project options, which enforces the use of fully qualified scope names.

 

In library code that needs to compile with compilers either side of XE2, where it can't be guaranteed that the user will have any default unit scopes defined, I use something like:

 

{$UNDEF RequiresUnitScopeNames}
{$IFDEF CONDITIONALEXPRESSIONS}
  {$IF CompilerVersion >= 24.0} // Delphi XE3 and later
    {$LEGACYIFEND ON}  // NOTE: this must come before all $IFEND directives
  {$IFEND}
  {$IF CompilerVersion >= 23.0} // Delphi XE2 and later
    {$DEFINE RequiresUnitScopeNames}
  {$IFEND}
{$ENDIF}

then in uses statements, for e.g.:

uses

  {$IFNDEF RequiresUnitScopeNames}
  Windows,
  Classes;
  {$ELSE}
  Winapi.Windows,
  System.Classes;
  {$ENDIF}

It's a pain, and it's easy to forget to add both versions of a unit name, but it works for me.

 

BTW the $LEGACYIFEND stuff is a work around for problems I encountered with the way $IFEND and $ENDIF work in XE3 and later! Your mileage may vary.

 

  • Like 1

Share this post


Link to post

On large projects in Delphi XE5 (later they have tried to make it more efficient) Unit scope names have had problems on large projects. the compiler literally tried with every prefix to locate every unit. When I have removed the scope names and changed the source to contain the full unit’s name with scopes, I was able to compile all projects in a project group without a problem.

Share this post


Link to post

You can have a lot of fun when starting to use namespaces.

 

This compiles fine ...

unit bla;

uses
  SysUtils;

interface

implementation

procedure Test;
begin
  SysUtils.Abort;
end;

... until you add the namespace to the unit name ...

unit bla;

uses
  System.SysUtils;

interface

implementation

procedure Test;
begin
  SysUtils.Abort;
end;

... but do you really want to write System.SysUtils.Abort ?

 

This is just an example. You don't of course need to qualify Abort, but if there are name clashes in different units you have to, or you can rely on the order of the units in the uses clause, which I think is a bad idea.

Share this post


Link to post
Posted (edited)
On 10/2/2024 at 6:43 PM, dummzeuch said:

 

... but do you really want to write System.SysUtils.Abort ?

 

But this would run fine too.

procedure Test;
begin
  Abort;
end;

It should be good enough to use fully qualified names only in cases of ambiguity, IMHO.
The compiler shows such cases.

 

But in the uses clause I always use fully qualified names.

Edited by Rollo62

Share this post


Link to post
1 hour ago, Rollo62 said:

It should be good enough to use fully qualified names only in cases of ambiguity, IMHO.

Even then this can be wrapped in a separate procedure (or whatever it is) with a non-colliding name published at a suitable location. When multiple occurrences have to be dealt with, the effort is merely the same with the benefit of better readability.

type
  TWinBitmap = Winapi.Windows.TBitmap;

procedure SysAbort; inline;
begin
  System.SysUtils.Abort;
end;

 

  • Like 1
  • Thanks 1

Share this post


Link to post
10 hours ago, Rollo62 said:

But this would run fine too.


procedure Test;
begin
  Abort;
end;

It should be good enough to use fully qualified names only in cases of ambiguity, IMHO.
The compiler shows such cases.

 

But in the uses clause I always use fully qualified names.

"Abort" is a popular name for procedures and methods, that's why it came to mind. I had to qualify it several times in my code because there was an ambiguity. I'm too lazy to use that qualifier without a good reason.

Uwe's answer looks like a good solution for these cases. I hope I remember it the next time this comes up.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×