namespace export vs global module

152 views
Skip to first unread message

Richard Smith

unread,
Jul 7, 2017, 9:24:16 PM7/7/17
to mod...@isocpp.org
Consider this module interface unit:

#include "some_library.h" // transitively contains eg namespace foo {...}
module M;

... and this module user:

import M;
// is the name ::foo visible here?
static int foo; // error?

Are all the namespaces from some_library.h supposed to be visible in the module user? Or is that rule only supposed to apply to namespaces under the purview of the module? It seems unfortunate to pollute the scope of a module user with namespace names from implementation details of the module interface -- this seems like the kind of accidental name leakage that modules should protect us from.


I wonder if the special case for namespace export is too broad. At the opposite end of the scale, we could say that a namespace declared in a module interface unit is exported if either (a) it is declared with 'export' or (b) it contains any exported declarations, and such a namespace is visible to other translation units in the same module if any declaration of that namespace occurs after the module-declaration. Is there a problem with that approach? I think that's more in line with what I'd expect as a naive user.


Alternatively, we could disallow exported declarations inside non-exported namespaces, and not make 'export' apply transitively to the contents of a namespace:

export namespace N {
  int a; // not exported
  export int b; // exported
}
namespace M {
  export int c; // error, enclosing namespace not exported
}

This would make it more explicit which names are exported from a module interface, at the cost of requiring seemingly-redundant 'export' keywords on most namespaces in the module interface.

Gabriel Dos Reis

unread,
Jul 8, 2017, 4:41:27 AM7/8/17
to mod...@isocpp.org
  • Are all the namespaces from some_library.h supposed to be visible in the module user? Or is that rule only supposed to apply to namespaces under the purview of the module? It seems unfortunate to pollute the scope of a module user with namespace names from implementation details of the module interface -- this seems like the kind of accidental name leakage that modules should protect us from.

 

Only the namespace-definitions under the purview of M.

 

  • we could say that a namespace declared in a module interface unit is exported if either (a) it is declared with 'export' or (b) it contains any exported declarations,

 

This is the intent, and I believe what is currently expressed in the spec.

 

  • and such a namespace is visible to other translation units in the same module if any declaration of that namespace occurs after the module-declaration.

 

Hmm, wouldn’t this require translating all module units “at once” somehow?   I would expect that for module interface partitions, but not necessary any module unit of the same module.

 

  • Alternatively, we could disallow exported declarations inside non-exported namespaces, and not make 'export' apply transitively to the contents of a namespace

 

My worry here is that it is heavy handed, given that namespaces span translation units (beyond module boundaries) already.

 

-- Gaby

--
You received this message because you are subscribed to the Google Groups "SG2 - Modules" group.
To unsubscribe from this group and stop receiving emails from it, send an email to modules+u...@isocpp.org.
To post to this group, send email to mod...@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/modules/.

Richard Smith

unread,
Jul 8, 2017, 6:57:52 PM7/8/17
to mod...@isocpp.org
On 8 July 2017 at 01:41, 'Gabriel Dos Reis' via SG2 - Modules <mod...@isocpp.org> wrote:
  • Are all the namespaces from some_library.h supposed to be visible in the module user? Or is that rule only supposed to apply to namespaces under the purview of the module? It seems unfortunate to pollute the scope of a module user with namespace names from implementation details of the module interface -- this seems like the kind of accidental name leakage that modules should protect us from.

 

Only the namespace-definitions under the purview of M.


OK, good.
 

 

  • we could say that a namespace declared in a module interface unit is exported if either (a) it is declared with 'export' or (b) it contains any exported declarations,

 

This is the intent, and I believe what is currently expressed in the spec.


[basic.namespace]p1 just says "A namespace with external linkage is always exported regardless of whether any of its namespace-definition is introduced by export." ... which suggests that even namespaces in the global module are exported. But I suppose the name lookup rule in [basic.scope.namespace]p1 actually only makes visible names that are in the purview of a module.

Still, this would be clearer if [basic.namespace]p1 explicitly said "A namespace with external linkage <ins>declared within the purview of a module</ins> is always exported [...]".


I'm still not clear on the intended treatment of an example like:

module M; // [[interface]] or whatever other syntax is chosen
namespace A {
  int n;
}

// separate TU
import M;
// is ::A declared here?
namespace B = A; // valid?

I think it would be preferable for this to be ill-formed: this leaks an unexported namespace name from the module interface to all of the module's users, with no apparent good path to an opt-out. The above being ill-formed (because A is not visible) follows from "a namespace declared in a module interface unit is exported if either (a) it is declared with 'export' or (b) it contains any exported declarations" but I don't think it follows from the current TS rules.

  • and such a namespace is visible to other translation units in the same module if any declaration of that namespace occurs after the module-declaration.

 

Hmm, wouldn’t this require translating all module units “at once” somehow?   I would expect that for module interface partitions, but not necessary any module unit of the same module.


I meant "occurs after the module declaration of the module interface", not after any module declaration for any TU in the module. (Eg, everything after the module-declaration in the interface unit is visible (after the module declaration) in all implementation units.)
 
  • Alternatively, we could disallow exported declarations inside non-exported namespaces, and not make 'export' apply transitively to the contents of a namespace

 

My worry here is that it is heavy handed, given that namespaces span translation units (beyond module boundaries) already.


Yes, also we don't want module ownership semantics for namespaces, so allowing / requiring them to be declared 'export' may be confusing.

Gabriel Dos Reis

unread,
Jul 9, 2017, 4:00:44 AM7/9/17
to mod...@isocpp.org
  • But I suppose the name lookup rule in [basic.scope.namespace]p1 actually only makes visible names that are in the purview of a module.

 

That is correct.

An export declaration is well-formed only in the purview of a module, so that covers against any other misinterpretation.

But I can see how the bits about a namespace with external linkage can be read/understood to be mean something different, and your clarifying amendment

 

  • "A namespace with external linkage <ins>declared within the purview of a module</ins> is always exported [...]".

 

sounds like a good starting point.  I will add to the module issue list.

 

  • module M; // [[interface]] or whatever other syntax is chosen

namespace A {

  int n;

}

 

// separate TU

import M;

// is ::A declared here?

namespace B = A; // valid?

 

 

Actually, that is well-formed (and the design calls for it to be well-formed), precisely thanks to the bits about a namespace with external linkage being exported regardless of whether it was lexically declared with ‘export’.

I believe this is necessary because of the fact that namespaces globally span translation units beyond module boundaries.

If we see a need for control of visibility restricted to module boundary, we should have lexical construct for that.  For example, at the Lenexa meeting, I suggested we make lexical room for things that should be ‘module internal’, e.g. ‘internal’ specifier or something to that effect.

 

  • I meant "occurs after the module declaration of the module interface", not after any module declaration for any TU in the module. (Eg, everything after the module-declaration in the interface unit is visible (after the module declaration) in all implementation units.)

 

OK, great!

 

  • Yes, also we don't want module ownership semantics for namespaces, so allowing / requiring them to be declared 'export' may be confusing.

 

Good.  That follows the model as explained above.

Richard Smith

unread,
Jul 10, 2017, 10:17:15 AM7/10/17
to mod...@isocpp.org
On 9 July 2017 at 01:00, 'Gabriel Dos Reis' via SG2 - Modules <mod...@isocpp.org> wrote:
  • But I suppose the name lookup rule in [basic.scope.namespace]p1 actually only makes visible names that are in the purview of a module.

 

That is correct.

An export declaration is well-formed only in the purview of a module, so that covers against any other misinterpretation.

But I can see how the bits about a namespace with external linkage can be read/understood to be mean something different, and your clarifying amendment

 

  • "A namespace with external linkage <ins>declared within the purview of a module</ins> is always exported [...]".

 

sounds like a good starting point.  I will add to the module issue list.


Thanks.
 
  • module M; // [[interface]] or whatever other syntax is chosen

namespace A {

  int n;

}

 

// separate TU

import M;

// is ::A declared here?

namespace B = A; // valid?

 

 

Actually, that is well-formed (and the design calls for it to be well-formed), precisely thanks to the bits about a namespace with external linkage being exported regardless of whether it was lexically declared with ‘export’.

I believe this is necessary because of the fact that namespaces globally span translation units beyond module boundaries.


I think it's a good idea to implicitly make a namespace name visible if it contains anything exported, but making it visible merely because it's declared in the purview of a module seems unnecessary. I suggested an alternative model earlier:

we could say that a namespace declared in a module interface unit is exported if either (a) it is declared with 'export' or (b) it contains any exported declarations

... and restricting this to only case (b) seems like another possible model (effectively: a namespace name is made visible by a module import if and only if that import also makes visible any names within the namespace).
Reply all
Reply to author
Forward
0 new messages