As is well known,, i am not the biggest fan of adding the namespace
keyword to the language solely so we can have namespaces in Swift. however! I am a big proponent of submodules and I just had an idea of how we can combine the two concepts and get two features with one keyword.
Right now, Swift has modules which have the concept of binary compatibility and distribution, and are equivalent to what other languages call packages. Modules are great for distributing full libraries and applications. However, they’re terrible as a tool for code organization. anyone who’s tried separating out all the low-level math code from their project into a separate module and seen performance fall off a cliff due to the new binary boundary knows this. What we really want is a way to group related code into submodules in a way that’s transparent to the compiler.
This sounds a lot like namespacing. What if namespaces could also be used as submodules? Here’s how i think it could work:
We declare a namespace with the keyword
namespace
, which can be prefixed with an access modifier like any actual Swift type.
public namespace Math
we place stuff in the namespace by prefixing its declared name with the namespace, separated by a dot
public struct Math.Vector {}
namespaces can be nested within each other too.
public namespace Math.Matrix
public struct Math.Matrix.Mat4 {}
just like everyone would expect, things inside the namespace don’t need the namespace qualifier to reference symbols in the same namespace
public func Math.Matrix.multiply(_ A:Mat4, _ B:Mat4) -> Mat4
{
...
}
since it would be tedious to prefix all your types like that if you want to make a submodule, which likely includes an entire folder of
.swift
files, we can use=
to specify a default namespace that all top-level declarations in the same file will automatically be placed under. (This is notusing namespace blah;
in C++, whose function is to resolve namespaces, not put things inside them.)
// matrix.swift
namespace = Math.Matrix
public func multiply(_ A:Mat4, _ B:Mat4) -> Mat4
{
...
}
this actually has the interesting side feature of allowing for an elegant syntax for rebinding namespace names within a file scope (equivalent to
import as
in Python). if this looks a lot like the syntax fortypealias
es, that’s because it does
namespace Matrix = Math.Matrix
public func Matrix.multiply(_ A:Mat4, _ B:Mat4) -> Mat4
{
...
}
By default, all
internal
and above namespaces are visible to all code within the same module. To encapsulate certain namespaces so that they must be explicitlyimported
to be used, we can add thefinal
modifier to their declaration. This creates a closed namespace, or a submodule.
final namespace MySubmodule
By default, things inside a submodule namespace can only reference symbols in the same submodule. Code that does not live inside any submodule can’t access symbols inside any submodule. (Although you can obviously define members of a submodule from anywhere.) To import things from another submodule, you use the
import
keyword. You can import symbols at the scope of any namespace.
namespace Math.Matrix(import Submodule1, import Submodule2.Bar)
you can import symbols into the top level like this
namespace(import MySubmodule.Foo)