I have a few base units, which I need to keep separate, but for ease of use I would like to group them into one unit. For now I have problem with enumeration types and helpers, not sure if anything else. Is it possible to make this work?
BaseUnit
type
TCustomEnum = (ceValue1, ceValue2, ceValue3);
TCustomEnumHelper = record helper for TCustomEnum
function AsString: string;
end;
GroupUnit
uses BaseUnit;
TCustomEnum = BaseUnit.TCustomEnum;
Usage in other units.
uses GroupUnit;
procedure DoSomething;
var
lValue : TCustomEnum;
begin
lValue := ceValue1; // doesn't work
lValue := TCustomEnum.ceValue1; // works
lValue.AsString; // doesn't work
end;
Your experimentation has yielded exactly what is to be expected.
The only reason your third unit has access to TCustomEnum
is because GroupUnit
declared a type alias using the same identifier but only that identifier. It's important to note that this is an important way in which the Delphi compilation process differs from C++. Whereas C++ recursively pulls all includes into the compilation scope, Delphi only pulls in the interface section of directly included units.
lValue := ceValue1;
doesn't work because the ceValue1
isn't defined in the compilation scope.lValue := TCustomEnum.ceValue1;
works because TCustomEnum
is pulled in in its entirety. That's to say because TCustomEnum
is equal to BaseUnit.TCustomEnum
: it means TCustomEnum.ceValue1
must be valid.
ceValue1
without any qualification. And there is no unqualified definition for that identifier in scope.lValue.AsString;
this doesn't work because the helper that makes AsString
available is not in scope.There are situations where declaring type aliases can be useful. But I must point out the the idea of general purpose grouping unit is deeply flawed.
Yes, it does reduce the number of units you have to use in order to pull a large1 number of dependencies. I.e. You think you're saving time by replacing uses Unit1, Unit2, Unit3, Unit4, Unit5, Unit6;
with the shorter uses GroupUnit;
.
But the large1 dependencies means you've also pulled in things you don't need. This leads to:
Find declaration...
only to get to the alias, and have to Find declaration...
again to find what you actually want.Yes, it seems like more work to list each and every thing you're using. But if you're using that many things that it's frustrating you should ask yourself: Why is my class so complicated? and then What's wrong with my design; how can I improve it?
As a final note, you can alias more than just the enum; provided you do so explicitly.
The following might suffice (but again, use it sparingly). Not least because it's so much work.
unit GroupUnit;
interface
uses BaseUnit;
type
TCustomEnum = BaseUnit.TCustomEnum;
TCustomEnumHelper = BaseUnit.TCustomEnumHelper;
const
ceValue1 = BaseUnit.ceValue1;
ceValue2 = BaseUnit.ceValue2;
ceValue3 = BaseUnit.ceValue3;