- DelphiTools - https://www.delphitools.info -

Introducing “unit namespace”

DWScript now has a new “unit namespace” feature, which aims at killing several birds with one stone:

The syntax is as follow:
unit namespace Foo.Bar; [deprecated 'deprecation message';]

uses Foo.Bar.One, Foo.Bar.Two, WhateverUnit;

and that’s all for the Foo.Bar.pas file. Unit namespaces don’t expose or implement anything.
With the above unit namespace, if in regular code you have

uses Foo.Bar, OtherUnit;

it will be equivalent to having written

uses Foo.Bar.One, Foo.Bar.Two, WhateverUnit, OtherUnit;

So all the unit namespace’s “uses” are brought into scope when the unit namespace is used.

Use for classic namespaces

In that case the unit namespace code will have to be auto-generated dynamically by your IDE or compiler environment, which will be responsible for collecting all the individual files that compose the namespace and presenting them in the unit namespace.

Unit namespaces files don’t have to be generated on disk or anywhere: you can just generate in memory in the DWScript event or interface you’re already using to feed source files. It’s just a way to tell the compiler all the source files that are part of a particular namespace.

Use for aggregated namespaces and conditional units

Unit namespaces are oblivious to what they’re made of, so you can aggregate unit from different namespaces.

Typical usage case is when some class defined in FooBar is using or referring other types defined in OtherUnit, and it’s common to need types of OtherUnit when using the class. You can use a unit namespace to bundle those as a convenience – just don’t got overboard and package everything and the kitchen sink!

Also, as unit namespace are source code, they support conditional directives ($ifdef, $include etc.), meaning you can use them for conditional compilation, depending on target.
Remember the Kylix era with Controls vs QControls in “uses” that had to be placed in all cross-toolset forms or components and controled with directives? If unit namespaces had been available, this conditionality could have be segregated rather than spread over every form.

Use for deprecation and refactoring

Suppose you want to rename FooBar to Foo.Bar, in Delphi you could use unit aliases, but that’s a compiler setting, and it won’t encourage or facilitate projects to be migrated. With unit namespaces you can rename FooBar to Foo.Bar and keep FooBar as unit namespace:

unit namespace FooBar deprecated 'Renamed to Foo.Bar with a dot!';

uses Foo.Bar;

and with it the old code will compile, with a deprecation warning, thus facilitating migration.

You can also leverage it for refactoring, f.i. if FooBar isn’t just renamed to Foo.Bar but also split into Foo.Bar and Core.Bar, f.i. if someone had put Core.* stuff into FooBar, and you’re cleaning that up. You can then introduce

unit namespace FooBar deprecated 'Splitted to Foo.Bar and Core.Bar';

uses Foo.Bar, Core.Bar;
This will keep the code compiling, just with a warning.
If you’re publishing libraries and don’t have control over all your library users’ code, this particular use case for “unit namespace” offers a lot of flexibility. Renaming and dispatching classes across units can now be a smooth process, with deprecation warnings that simplify migration of user code.