C++ Logo


Advanced search

Re: [isocpp-core] unimported implementation partitions

From: Mathias Stearn <redbeard0531_at_[hidden]>
Date: Thu, 9 Jun 2022 00:16:57 +0200
On Wed, 8 Jun 2022 at 23.32 Daniel Ruoso <daniel_at_[hidden]> wrote:

> 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 standard seems pretty precise in its definition of that term. If you
disagree then I think you should file a core issue because its definitions
should be precise.

> 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

You’ve said the phrase “the implementation unit” a few times and that
implies there is exactly one. Is this a typo or are you trying to describe
something specific other than one of the zero or more implementation units?

, 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).

I don’t think that is true. For example I think this is a valid program.

module m;
void foo() {}

module m;
void foo();
void bar() {foo();}

export module m;
export void bar();

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.

But what you are calling internal units still *are* implementation units. I
agree with that grouping, however the second group should really be given a
name that doesn’t also include some members of the first. I’ve used the
terms nun-importable unit and pure implementation unit, but I don’t love

Don’t mistake me as being a fan of implementation partitions. I
unsuccessfully argued that we should remove them from c++20, and still wish
they weren’t a thing. But since they are, I think we should be careful with
terminology and not use words to mean something different from their
definition in the standard (“specialization” and “static init” are bad
precedents that lead to a lot of ambiguity and confusion).

> 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.
> daniel

Neither of those programs is well formed. Both violate the first sentence

If I add an export to make :interfacepart be an interface, then I think I
see what you are saying but I still disagree. I forgot to mention that when
adding a partition to an implementation unit’s modules declaration you also
need to add the explicit import of the PMI that you were getting implicitly
http://eel.is/c++draft/module.unit#8. If you add that (and the missing
export) then I think the first program becomes valid.

Also I think in the first program there is no need to import :part1, and in
the second there is no need to have any explicit imports in the pure
implementation unit.


Received on 2022-06-08 22:17:09