April 03, 2014
On 4/3/14, Walter Bright <newshound2@digitalmars.com> wrote:
> A possible enhancement would be to allow (for all templates with no
> parameters):
>
>      nspace.foo();

My only problem with this is how it will affect existing code. E.g.:

template take(alias templ) { }
template take(T) { }

template Empty() { struct Empty { } }

take!Empty;  // which overload of take is instantiated?
April 03, 2014
On 2014-04-03 03:48:18 +0000, Walter Bright <newshound2@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@michelf.ca
http://michelf.ca

April 03, 2014
V Thu, 3 Apr 2014 06:36:54 -0400
Michel Fortin <michel.fortin@michelf.ca> napsáno:

> On 2014-04-03 03:48:18 +0000, Walter Bright <newshound2@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).
> 
> 

I think we should distinguish modules lookup from namespaces lookup. Something like this:

A.B.foo() // call foo function from module/struct/class A and B
#A.#B.foo // call foo function from namespaces A and B
or
A::B.foo // call foo function from namespaces A and B
or
/A/B.foo // call foo function from namespaces A and B

April 03, 2014
"Walter Bright"  wrote in message news:lhi1lt$269h$1@digitalmars.com...

> Here's Andrei's proposal:
>
>      extern (C++) template nspace() {
>          int foo();
>      }

This is really ugly and complicated.

Why not just

pragma(cpp_namespace, "outer")
{
   pragma(cpp_namespace, "inner")
   {
       extern(C++) void func();
   }
}

which is trivial to implement and doesn't require parser or semantic changes?

Adding syntax for actual namespaces to D is a different beast and IMO not worthwhile. 

April 03, 2014
On 03/04/14 00:07, Walter Bright wrote:
> Here's Andrei's proposal:
>
>      extern (C++) template nspace() {
>          int foo();
>      }
>
> It would be accessed in D by:
>
>     nspace!().foo();
>
> A possible enhancement would be to allow (for all templates with no
> parameters):
>
>      nspace.foo();
>
> Note that:
>
>      template nspace() {
>          extern (C++) int foo();
>      }
>
> would not put foo() in a C++ namespace, although it would still be
> accessed from D as:
>
>      nspace.foo();
>
> One downside of this proposal is that if we ever (perish the thought!)
> attempted to interface to C++ templates, this design would preclude that.

I like using a UDA or pragma better:

@namespace("nspace")
{
    extern (C++) int foo ();
}

Or

pragma(cpp_namespace, "nspace")
{
    extern (C++) int foo ();
}

Then it's also possible to use this syntax:

@namespace("nspace"):

extern (C++) int foo ();

The only advantage I can see with using "template" is that templates can be mixed in, it would be similar to the using declarative in C++.

-- 
/Jacob Carlborg
April 03, 2014
I am not sure what is the best option, but it should be readable and obvious. So I might prefer to just have "::" if possible. Somewhat annoying and verbose, so I am not sure about this, but the advantage is that it is easy to see what is C++ and what is D function calls.
April 03, 2014
On Thursday, 3 April 2014 at 03:48:08 UTC, Walter Bright wrote:
>> 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.

A solution could be to allow this:

----
module foo {
    module bar {
        // equivalent to foo/bar.d
    }
}
extern(C++) module bar {
    // Equivalent to namespace bar {} in C++
}
----

Note that Rust does something similar to this to allow multiple modules to be defined in a single file (though Rust also doesn't have the correspondence between filesystem location and module like D does - perhaps this is acceptable with the introduction of package.d?)

Robert
April 03, 2014
On 4/3/2014 3:36 AM, Michel Fortin wrote:
> 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).

You have a good point in that to go all the way with namespaces, we'd have to implement Koenig lookup and support insertion of names into previous namespaces.

I can't see this happening in D.

But I don't see that as much of an argument to not do simple scoping with namespace lookup.

April 03, 2014
On 4/3/2014 4:06 AM, Daniel Kozák wrote:
> I think we should distinguish modules lookup from namespaces lookup.
> Something like this:
>
> A.B.foo() // call foo function from module/struct/class A and B
> #A.#B.foo // call foo function from namespaces A and B
> or
> A::B.foo // call foo function from namespaces A and B
> or
> /A/B.foo // call foo function from namespaces A and B


Please, no!
April 03, 2014
On Thursday, 3 April 2014 at 19:44:02 UTC, Walter Bright wrote:
> On 4/3/2014 4:06 AM, Daniel Kozák wrote:
>> I think we should distinguish modules lookup from namespaces lookup.
>> Something like this:
>>
>> A.B.foo() // call foo function from module/struct/class A and B
>> #A.#B.foo // call foo function from namespaces A and B
>> or
>> A::B.foo // call foo function from namespaces A and B
>> or
>> /A/B.foo // call foo function from namespaces A and B
>
>
> Please, no!

Ok, just an idea :)