The Modules TS gives declarations an explicit owner
The January Modules TS draft specifies named dependencies and exported declarations. Its ownership and lookup rules explain why importing a module changes more than the spelling of an include.
A header gives several translation units copies of a declaration without giving the language an explicit dependency on the component that owns it. The January 29 Modules TS working draft, N4720, addresses that missing relationship. It specifies named modules, interfaces and imports as extensions to C++17. The draft is an experimental specification, not a statement that modules have become part of the published C++ language standard.
The earlier design paper, P0142R0, explains the problem in terms of componentization and repeated processing. Its authors are Gabriel Dos Reis, Mark Hall and Gor Nishanov. N4720 identifies that design and implementation as part of its basis. Reading the rationale alongside the working draft helps explain why the specification changes linkage and lookup as well as adding syntax.
Templates give C++ abstractions that can avoid runtime cost, but compile time and diagnostics remain substantial concerns for me. A module design matters if it lets the compiler process a declared interface with less dependence on the textual environment of each consumer. The draft's semantic rules are necessary to that goal, independently of any eventual build-time improvement.
Textual inclusion leaves the component implicit
P0142R0 describes the conventional linking model through independently compiled translation units. A consumer declares a function and the linker resolves its external name against a definition supplied elsewhere. The consumer's source does not necessarily name the translation unit or component that should provide that definition.
Headers reduce the chance that separate declarations disagree, but their contents are still processed within each including translation unit. The design paper identifies repeated processing and macro dependence as consequences. A header's meaning can depend on the macros established by its consumer, so a tool cannot always interpret the header without that surrounding configuration.
The proposed module mechanism adds a symbolic dependency. An import identifies a module by name. The module's interface determines which declarations it makes available. That lets the language describe a relationship that an ordinary external declaration leaves implicit, while retaining separate translation and eventual linking.
The rationale does not propose removing the preprocessor. It explicitly treats coexistence with existing inclusion-based code as necessary. That constraint explains why a practical module design needs rules for the boundary between old declarations and module-owned declarations, instead of assuming every library can immediately be rewritten.
Export identifies declarations available to consumers
N4720 gives a module interface unit an export module declaration. Export declarations within its purview identify the interface. A minimal pair of translation units, using the draft's syntax, is:
// Module interface unit.
export module arithmetic;
export int square(int value) { return value * value; }
// A separate importing translation unit.
import arithmetic;
int main() { return square(3); }
The consumer imports the named module and can find the exported function. The example deliberately uses an input whose multiplication fits in int. Its purpose is to show the dependency and export mechanism, not to introduce a policy for overflow or a compiler-specific build command.
An export declaration does not establish a new scope. Exported names remain in their declared namespaces and contexts. Import likewise does not put everything in a namespace bearing the module's name. A module name identifies a component in the dependency system, while namespaces continue to organize ordinary C++ names.
The draft also limits export declarations to namespace scope within a module interface unit's purview. It rejects exports within an unnamed namespace and declarations that explicitly give the exported entity internal linkage. Those constraints prevent export from becoming a general instruction to override an entity's earlier linkage choices.
Ownership constrains redeclarations across modules
N4720 attaches declarations to modules and defines ownership rules for the entities they introduce. A matching declaration attached to another module can make the program ill-formed. This is a substantive restriction on the old practice of independently supplying a matching declaration wherever a name is needed.
The draft illustrates that rule with an exported function followed by a matching declaration in another translation unit that imports its module. The second declaration cannot simply pretend that it is independently declaring the same globally owned entity. Module attachment is part of the semantic relationship that the compiler checks.
This gives ownership a practical role in consistency. A declaration's spelling and signature no longer carry all the relevant information. Which module supplied it can matter as well. That is why the feature cannot be fully described as replacing an include directive with an import statement.
The specification also contains a proclaimed-ownership declaration, written with extern module, for naming an entity associated with another module. Its examples use forward declarations to address circular relationships between types. That mechanism belongs to this TS draft and should be discussed as such, without assuming the syntax of some later module system.
Importing a dependency does not automatically re-export it
The draft distinguishes an ordinary import from an exported import. An ordinary import in a module interface does not make the imported names transitively visible to consumers of that module. An exported import makes the other module's exported names available as though the consumer had imported it too.
That distinction gives an interface author control over the names its clients can use. A dependency needed to implement or describe part of a module does not automatically become a new dependency clients can name through that module. Re-export is an explicit operation with its own lookup consequences.
N4720 also prohibits a module from having an interface dependency on itself. Its examples include an indirect cycle through several modules. The rule concerns semantic interface dependencies, not merely whether a set of source files can be located by a build tool.
I find these explicit relationships useful in a language where a large codebase can contain several styles of organization at once. A consumer should be able to identify which component supplies a declaration and which dependencies the component exposes. The TS gives those questions language rules while leaving the external representation of translated modules to implementations.
The draft explicitly says that source files, translation units and translated units need not have a one-to-one file representation. It also leaves implementation-defined whether a module interface's source must be available to an importing translation unit. Those boundaries separate the specified program semantics from a particular compiler's artifact format or build workflow.