Specifying C++ symbols in C++ namespaces

Michel Fortin michel.fortin at michelf.ca
Thu Apr 3 03:36:54 PDT 2014


On 2014-04-03 03:48:18 +0000, Walter Bright <newshound2 at digitalmars.com> said:

> On 4/2/2014 7:14 PM, Michel Fortin wrote:
>> That's a contrived example.
> 
> Not at all. The whole point of using namespaces in C++ is to introduce 
> a scope. And the whole point of scopes is to have the same name in 
> different scopes represent different objects.
> 
>> Perhaps I'm wrong, but I'd assume the general use
>> case is that all functions in a module will come from the same C++ namespace.
> 
> I believe that is an incorrect assumption. C++ namespaces were 
> specifically (and wrongly, in my not so humble opinion, but there it 
> is) not designed to be closed, nor have any particular relationship 
> with modules.
> 
>> Alternatively you can use another module for the other namespace.
> 
> Forcing C++ code that exists in a single file to be split up among 
> multiple D files is inflicting unnecessary punishment on the poor guy 
> trying to justify migrating to D.

Ok, let's assume that we actually want to reproduce the C++ file 
structure then. Let us have a C++ project, with two files. I'll 
temporarily use the 'namespace' keyword on the D side until we can 
decide on how to best represent a namespace:

      module foo;
      extern (C++):

      namespace S { namespace T {
         int foo();
         namespace U {
             int foo();
         }
      } }


      module bar;
      extern (C++):

      namespace S { namespace T {
         int bar();
         namespace U {
             int bar();
         }
      } }

Now let's use those:

      module main;
      import foo;
      import bar;

      void main() {
          S.T.foo();
          S.T.U.bar();
      }

But how does the lookup for those functions work? If we use structs or 
templates to represent those namespaces in D then you'll have to 
specify the module name to disambiguate the struct/template itself, and 
the namespace just becomes a nuisance you have to repeat over and over:

      void main() {
          .foo.S.T.foo();
          .bar.S.T.U.bar();
      }

Here I'd argue that having whole-module namespaces in D makes no sense. 
So let's retry by peeling the "S.T" part of the namespace:

      module foo;
      extern (C++, S.T):

      int foo();
      namespace U {
          int foo();
      }


      module bar;
      extern (C++, S.T):

      int bar();
      namespace U {
          int bar();
      }


      module main;
      import foo;
      import bar;

      void main() {
          foo();
          .bar.U.bar();
      }

Better. Still, if you want C++ namespaces to work nicely, you'll have 
to introduce first class namespace support in D. That means that 
identical namespaces are "merged" into each other when you import 
modules that contain them. It'd allow you to write this:

      void main() {
          foo();
          U.bar();
      }

Still, I'm not convinced that'd be terribly helpful. Namespaces in D 
would make it easier to declare things 1:1 for sure, but anything that 
depends on Koenig lookup[1] will be broken in D. It could even be 
silently broken as no Koenig lookup means another function not in a 
namespace could be used silently instead of the expected one in a 
namespace (assuming a naive port of some C++ code).

[1]: https://en.wikipedia.org/wiki/Argument-dependent_name_lookup

I'd tend to simply implement extern(C++, namespace.here), which should 
work fine to wrap single-namespace cpp files, and wait to see what are 
the actual friction points before introducing more (people can 
experiment with structs or other modules meanwhile).


-- 
Michel Fortin
michel.fortin at michelf.ca
http://michelf.ca



More information about the Digitalmars-d mailing list