An Enum Based Approach to Namespaces

is introducing a new namespace (anywhere) a common occurrence though? namespaces are big domains, in my experience we’ve gotten the most mileage out of namespaces that contain hundreds, if not thousands of declarations.

i once stuck to “one namespace per module”. but as you’ve also discovered, namespaces that span many modules are far more useful. in code bases with a few, large namespaces, introducing new namespaces will naturally be a rare event.

Absolutely, all the time. The use cases I'm most interested in solving for are those where you have, say, a large monorepo where multiple independent teams are working on a wide variety of components. In C++ and Java, for example, it's extremely common for a codebase to pull in a new dependency from some other team that uses a namespace/package that wasn't previously introduced.

But I don't think one's imagination needs to be limited to very large codebases here. We could do a thought exercise of revisiting the design of the Swift standard library and breaking it up into smaller modules. Strings would live in some module—perhaps a "core" module or a specific strings module. We'd have Unicode APIs, but maybe we consider some of those to be fairly specialized, so we want to contain them in a Unicode namespace (let's assume they can't be in a separate module because there is necessary coupling between the Unicode APIs and the string APIs). Then, let's say we introduce a Regex module for those APIs. There are some specialized Unicode APIs for regular expressions as well, so we can imagine that it'd be nice to have a Unicode namespace there as well. Furthermore, it would be nice if someone importing both the core/strings modules and the Regex module could use the merged Unicode namespace without any ambiguity.

If we consider this to be a realistic organization, then using a hack like introducing yet another module just to define a single enum doesn't seem like a clean or friendly approach. It may "work" in some cases given the limitations of the language today, but it's by no means a desirable solution.

1 Like

let’s suppose we want to declare namespaces without creating namespace modules. what would be the fully-qualified name of declarations that use that namespace?

today the answer is straightforward:

_ImageProcessing.ImageProcessing.JPEGDecoder
_ImageProcessing.ImageProcessing.PNGDecoder
_ImageProcessing.ImageProcessing.GIFDecoder

you could link to them in DocC with

``/_ImageProcessing/ImageProcessing/JPEGDecoder``
``/_ImageProcessing/ImageProcessing/PNGDecoder``
``/_ImageProcessing/ImageProcessing/GIFDecoder``

and you could exclude the docs from Googlebot with

User-agent: Googlebot
Disallow: /docs/swift-image-processing/_imageprocessing/

but if namespaces are no longer associated with modules, then we can only qualify names with the name of the modules that declares the type. this means:

JPEG.ImageProcessing.JPEGDecoder
PNG.ImageProcessing.PNGDecoder
GIF.ImageProcessing.GIFDecoder

which loses the ability to prefix-match on the namespace.

one idea that might occur to us, is to use the namespace itself as a qualifier - after all that is what namespaces are for!

ImageProcessing.JPEGDecoder
ImageProcessing.PNGDecoder
ImageProcessing.GIFDecoder

but then you would have to ensure that the namespaces do not collide with any module names anywhere else. and we are back to the old problem of needing global knowledge to manage namespaces.

The solution to this is adding a namespace resolution operator (::) and an unnamed alias for the current module (possibly even just _::). This is a separate issue that needs to be addressed regardless of whether and how namespaces are implemented.

For instance, this:

_::ImageProcessing.JPEGDecoder
_::ImageProcessing.PNGDecoder
_::ImageProcessing.GIFDecoder

Would guarantee that ImageProcessing can't clash with a module, since it's being looked up explicitly in the context of the current module and we can't nest modules.

4 Likes