C++ Logo


Advanced search

Re: [isocpp-core] unimported implementation partitions

From: Daniel Ruoso <daniel_at_[hidden]>
Date: Wed, 8 Jun 2022 17:32:03 -0400
Em qua., 8 de jun. de 2022 às 16:47, Mathias Stearn
<redbeard0531_at_[hidden]> escreveu:
> http://eel.is/c++draft/module.unit seems pretty clear that both are
> implementation units. AFAICT implementation partitions are basically
> the same as implementation non-partitions that gain the ability to be
> imported and lose the implicit import of the PMI.

Reachability, scope of declaration and linkage of an internal
partition (i.e.: the file with `module foo:bar`) is the same as with
interface partitions (the only difference being that it can't
contribute to the external interface).

So it's a bit more than "gain the ability to be imported", the
semantics of the declarations are very different than the semantics of
declarations in a module implementation unit (i.e.: the file with
`module foo`).

> Is here some wording you can point me to that makes this “fundamental
> difference” clear? Or wording that would justify having that source
> modification change the semantics of an otherwise unmodified program?

Unfortunately the text of the standard is not very precise when it
uses the term "implementation unit".

The feeling I have is that folks wanted to create a symmetry matching
what we see in the .h/.cpp pairs of files, where you would have the
module interface units (primary and partition) be the equivalent of
the header, and the module implementation units (including internal
partitions) to be the equivalent of the .cpp files. And the wording
seems to attempt to communicate something like that.

However that's not what the outcome of how things were designed.

The distinction between the interface units (primary and partitions)
and the internal partition is more akin to "public" and "private"
headers. The internal partition is declaring things to be used in
other translation units, and it doesn't really contribute to the
module if it's not imported anywhere.

The implementation unit, however, does maintain the symmetry with the
.cpp files. Any new declaration made on that translation unit is only
visible there, and the purpose of that file is to provide the
definition for any of the declarations that didn't have a definition
before (in any of the primary interface, interface partition, and
internal partitions). And then you can have several implementation
units, all in the same module purview.

In other words. The grouping we can make is that we have "importable
units", with primary interface, interface partition and internal
partitions (and header units), and then we have "implementation units"
as a separate group.

For instance, it doesn't really make sense to have the following three
translation units:

 module m:interfacepart;
 export void foo();

 module m:part1;
 void foo() {};

 export module m;
 import m:part1;
 export import m:interfacepart;

You actually have an ill-formed program because "An exported
redeclaration of a non-exported declaration of an entity is
ill-formed." (10.2.6)

Instead, what you need to do is:

 module m:interfacepart;
 export void foo();

 module m;
 import :interfacepart;
 void foo() {};

 export module m;
 export import :interfacepart;

So yeah, changing `module m` to `module m:part` would break an
otherwise working program.


Received on 2022-06-08 21:32:15