A lot of people (me included) complained about the support (or lack of support)
for namespaces in Delphi for .NET when Delphi 8 was initially released. Namespaces
essentially boiled down to a fancy name for "dots in the unit name" in
Delphi 8, forcing every unit to use a unique "namespace" name and
generally treating namespaces as units.
Delphi 2005 was released late last year and majorly revamped the way namespaces
work, allowing more flexibility and allowing several units to populate the same
namespace (a necessity when developing libraries for consumption by non-Delphi users),
but the way Delphi 2005 handles namespaces is awkward, to say the least, and counter-intuitive
to the extend that when i saw it described the first time, i had to read the info
several times to even begin wrapping my head around it.
When we set out to design Chrome early last year, one of our goals was to
provide proper namespace support for the Pascal language, namespace support that
would seamlessly integrate into the way the CLR handles namespaces and would be
familiar and intuitive for user familiar with C#. Also, it was important to us that
Chrome would allow the creation of libraries that could intuitively be used by both
Chrome users and users of other languages such as C#, Visual Basic and, yes, Delphi
for .NET.
So i want to take this opportunity to compare namespace support in Delphi 2005 and
Chrome, and point out the design decisions we made for Chrome in order to make its
namespace support as intuitive as possible. This comparison breaks down into 6 major
points:
(1) In Chrome, what you see is what you get. If you type "namespace
x.y.z", that’s your namespace.
In Delphi, namespace names and unit names are separate things. If you have units
"x.y.z" and "x.y.a" (which incidentally have to
be named "x.y.z.pas" and "x.y.a.pas"), the actual namespace
will be "x.y".
To make things more confusing, if you now want to use a type from these, then in
Delphi you still have to specify the unit name (ie "uses x.y.z, x.y.a;"),
while from all other languages you will use the namespace name (ie "using
x.y;" in C#, "uses x.y;" in Chrome, etc). If you’re a 3rd party
developer deploying your library to other developers, you’ll have to provide separate
docs with separate class names for Delphi vs. other users. Confused yet?
(2) While inside Delphi (ie not consuming Delphi code form other languages),
you lose pretty much all the benefits of namespaces; you have to use the full unit
names, as mentioned above. Also, you cannot have circular references between the
units that "make up the namespace".
By contrast, in Chrome you can use the same namespace name in as many file headers
as you’d like and – whether in the same project or when consuming the .dll from
another Chrome/C#/whatever project – these files are treated as one big namespace;
all the classes can see and reference each other; circular references are not an
issue.
(3) Even between different namespaces, circular uses clauses are not an issue.
So you can have "uses b;" in one or more files of "namespace
a;" and "uses a;" in one or more files of "namespace
b;" without any worries. This finally allows to conveniently spread class
hierarchies to several files even of the classes need to reference each other –
a common problem in Delphi – and classic Object Pascal in general – that could only
be worked around by placing all classes in a single file.
(4) Regardless of the namespace that’s set for a given file using the "namespace"
keyword, you can always declare classes into any other arbitrary namespace by using
the full name in the class declaration and method implementations, allowing you
to have classes from a single file go into separate namespaces (a rare requirement,
granted, but it does come in handy at times).
(5) To access a type in Delphi, you MUST have its namespace in the uses clause
– even if you use the full class name. so "x := System.Some.Obscure.MyObject.Create(…);"
will not work in Delphi, unless you also have "System.Some.Obscure"
listed in the uses clause (which of course makes the repetition of "System.Some.Obscure"
in the Create statement redundant). Another example of the unit-centricity of Delphi’s
namespaces.
In Chrome, you don’t need this; all available types (i.e. types from all referenced
assemblies and all types defined in the current project) are available at ANY place
where you could use a type name, via their full name – regardless of whether their
namespace is in the uses clause or not; you only need to "use" the namespace
if you want to refer to the types via the short name (ie as "x := new MyObject(…);"
without the namespace prefix.
(6) Finally, as a convenience feature for using large nested namespace hierarchies,
Chrome allows the use of the * wildcard in it’s uses clause, to use an entire namespace
hierarchy. As a result, "uses System.Xml.;*" for example gives
access to the entire set of Xml classes – including those located in sub-namespaces
such as System.Xml.XPath.
I hope the above gave you a quick overview of how namespace support works in Chrome,
and what benefits it offers over Delphi 2005’s awkward namespace system. If you
have any questions or suggestions, please let me know.
Also, be sure to check out our March Preview of the free Chrome command line compiler,
to see the Chrome language in action, now!