C++ Logo


Advanced search

Re: P2581R0: Specifying the Interoperability of Binary Module Interface Files

From: Daniel Ruoso <daniel_at_[hidden]>
Date: Sat, 7 May 2022 11:44:38 -0400
Em sex., 6 de mai. de 2022 às 15:41, Iain Sandoe <iain_at_[hidden]> escreveu:
> > On 6 May 2022, at 19:55, Daniel Ruoso via SG15 <sg15_at_[hidden]> wrote:
> > 1.3. "Internal Module Partition Units": The translation units
> > with "module foo:bar"
> .. IMHO the last iteration was closer.
> The standard clearly says these are implementation units, it does not mention
> ‘internal’ AFAICS. They contain a partition, therefore ‘partition implementation’
> (or the reverse word order, if that’s concensus) seems reasonable.

Yes. But the use of the term "implementation" creates a false symmetry
with the "Module Implementation Units".

IOW, the distinction between "module Foo;" and "module Foo:Bar;" is
substantially larger than what the distinction between "Module
Implementation Unit" and "Module Implementation Partition Unit"

Specifically, a unit with "module Foo:Bar:" is still declaring things
that are not declared anywhere else and that may be imported by either
the "Primary Module Interface Unit" or by any other "Module Interface
Partition Units".

>From a practical point, a unit with "module Foo;" never generates a
bmi, while a unit with "module Foo:Bar;" always generates a bmi.

That asymmetry is even more clear when you consider that if you have
the following unit:

module Foo:Bar;
void f();

The unit that contains the definition for `f` would look like:

module Foo;
import :Bar;
void f() { ... }

So while it is true that a unit with `module Foo:Bar;` doesn't
contribute to the "external interface" of the module, it may still be
reachable by that external interface, and therefore it would need to
be distributed alongside the interface (primary and interface

Consider the following example:

export module Foo;
import :Bar;
export void g() { internal_g(); }
export void h();

module Foo:Bar;
void internal_g();
void internal_h() {};

module Foo:Baz;
void unreachable_g() {}

module Foo;
import :Bar;
import :Baz;
void h() { internal_h() };
void internal_g() { unreachable_g(); };

Maybe it would be useful to give different names for internal
partitions depending whether or not the Primary Module Interface Unit
or any Module Interface Partition Units imports that partition
(Foo:Bar vs Foo:Baz in the example above). As a partition that is
never reachable from the "external interface" doesn't need to be
distributed with the interface units, strictly speaking. But I would
argue those two types are still "Module Internal Partition Units".

>From a library design consideration, one may consider that it would be
more correct to categorize the internal partition that is only
reachable from the implementation unit to be grouped closer to the
implementation unit. However, from a tooling consideration, I would
argue the behavior of the unit in regards to how the tools have to
consider it (i.e.: generates bmi or not) takes precedence. IOW, it's
fine if the distinction between "importable" and "non-importable"
units exists only on the tooling space.

The way the distinction between reachable and unreachable internal
units would materialize in the work-in-progress CMake implementation,
for example, is that you would have different PUBLIC and PRIVATE file
sets, such that Foo:Bar would be in the PUBLIC file set, while FOO:Baz
would be in the PRIVATE file set.


Received on 2022-05-07 15:44:51