[swift-evolution] [Proposal] Qualified Imports and Modules

Brent Royal-Gordon brent at architechies.com
Mon Jul 18 19:26:00 CDT 2016

> On Jul 18, 2016, at 4:50 PM, T.J. Usiyan <griotspeak at gmail.com> wrote:
> * You may need to split a single submodule across multiple files, but this rule doesn't allow that.
> You can, internally, have several modules and then create one that imports those smaller ones publicly with the name that you desire. 

They wouldn't have access to each others' internal scopes by default, would they?

In general, I get the sense that this proposal is hostile to the current idea that a module (or submodule) consists of multiple files, each of which has both intra-file privacy and inter-file sharing with other parts of the module. I think this is a natural and extremely useful way to design software. Moreover, I think throwing this concept out goes explicitly against the grain of current Swift access control mechanisms. In a world where every file is its own module, what's the difference between `internal` and `fileprivate`? Are we going to end up in an Objective-C-style situation of giant import lists at the top of every file, listing stuff that's in the same module? Doesn't that go against the goal of reducing boilerplate?

I would prefer to see:

1. Each file is allowed one `submodule` declaration as the first non-comment line of code in the file. It does not include the main module name, only the submodule name (so `UIKit.UIGestureRecognizerSubclass` would simply have `submodule UIGestureRecognizerSubclass` at the top). If there is none, the file is part of the main module. (It *might* make sense to have both public submodules, which anyone can import, and internal submodules, which can only be imported within the top-level module, but I'll need to think about that.)

2. Filenames are freeform; any file can declare itself to belong to any submodule. Obviously, best practice would be to give your files sensible names that have some kind of link to the submodule name, but this would be a linter concern.

3. Each submodule has its own `internal` scope. Submodules can import the `internal` scopes of specific peer modules with an annotation like `@testable` (but probably renamed). Tests are treated as a submodule of the main module, so they can participate in this mechanism just like everyone else.

4. `import` only ever imports the `public` (or `internal`, with the `@testable` equivalent) symbols in the specified submodule. It re-exposes them with the access modifier on the `import` statement, or `private` by default. It does not re-expose `internal` symbols as `public`. `using`, `hiding`, and `renaming` apply to all comers, not just the current file.

I think this approach would harmonize much better with current Swift features and code organization practices, while offering several new features (umbrella modules, exposing certain symbols only when a submodule is explicitly imported, multiple `internal` scopes within a top-level module) which would be very useful.

Brent Royal-Gordon

More information about the swift-evolution mailing list