www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Specifying C++ symbols in C++ namespaces

reply Walter Bright <newshound2 digitalmars.com> writes:
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.
Apr 02 2014
next sibling parent "w0rp" <devw0rp gmail.com> writes:
Seems alright. The only downside I can think of is that the 
namespace wouldn't be semantically analysed until you first try 
to use it, as it's a template.
Apr 02 2014
prev sibling next sibling parent reply "monnoroch" <monnoroch gmail.com> writes:
And what about something like static struct? It seems more 
natural and less hacky to me.
Apr 02 2014
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/2/2014 3:30 PM, monnoroch wrote:
 And what about something like static struct? It seems more natural and less
 hacky to me.

Because C++ mangles static member functions of structs differently from members of namespaces.
Apr 02 2014
prev sibling next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Walter Bright:

 Here's Andrei's proposal:

     extern (C++) template nspace() {
         int foo();
     }

I suggest to brainstorm the syntax some more time, because someone could be able to invent a better syntax. Some seeds: extern (C++(nspace)) { int foo(); } extern (C++) struct nspace { int foo(); } extern (C++)(nspace) { int foo(); } extern (C++ nspace) { int foo(); } Bye, bearophile
Apr 02 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/2/2014 3:33 PM, bearophile wrote:
 I suggest to brainstorm the syntax some more time, because someone could be
able
 to invent a better syntax.

 Some seeds:

 extern (C++(nspace)) {
      int foo();
 }

I considered that, but it fails because: C++: namespace S { namespace T { int foo(); namespace U { int foo(); } } } D: extern (C++, S.T) { int foo(); extern (C++, U) { int foo(); } } foo(); // error, ambiguous, which one? S.T.foo(); // S undefined
 extern (C++) struct nspace {
      int foo();
 }

Fails because a struct as struct and struct as namespace are not distinguishable.
Apr 02 2014
parent reply Michel Fortin <michel.fortin michelf.ca> writes:
On 2014-04-03 01:09:43 +0000, Walter Bright <newshound2 digitalmars.com> said:

 I considered that, but it fails because:
 
 C++:
 
      namespace S { namespace T {
          int foo();
          namespace U {
              int foo();
          }
       } }
 
 D:
 
    extern (C++, S.T) {
        int foo();
        extern (C++, U) {
          int foo();
        }
    }
    foo();  // error, ambiguous, which one?
    S.T.foo(); // S undefined

That's a contrived example. 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. For the contrived example above, I think it's fair you have to use a contrived solution: module s.t; extern (C++, S.T): int foo(); struct U { static extern (C++, S.T.U): int foo(); } Alternatively you can use another module for the other namespace. -- Michel Fortin michel.fortin michelf.ca http://michelf.ca
Apr 02 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/2/2014 7:14 PM, Michel Fortin wrote:
 On 2014-04-03 01:09:43 +0000, Walter Bright <newshound2 digitalmars.com> said:
 I considered that, but it fails because:

 C++:

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

 D:

    extern (C++, S.T) {
        int foo();
        extern (C++, U) {
          int foo();
        }
    }
    foo();  // error, ambiguous, which one?
    S.T.foo(); // S undefined

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.
 For the contrived example above, I think it's fair you have to use a contrived
 solution:

I don't believe that punishing C++ users who dare to try D is the path to success for D :-)
 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.
Apr 02 2014
parent reply Michel Fortin <michel.fortin michelf.ca> writes:
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
Apr 03 2014
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
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.
Apr 03 2014
parent Michel Fortin <michel.fortin michelf.ca> writes:
On 2014-04-03 19:43:23 +0000, Walter Bright <newshound2 digitalmars.com> said:

 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.

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

What I'm saying is that it should be optional to create a new scope to declare a C++ function from a namespace. In other words you need to be able to put the function at module scope in D. -- Michel Fortin michel.fortin michelf.ca http://michelf.ca
Apr 03 2014
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
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!
Apr 03 2014
prev sibling next sibling parent "Xiaoxi" <xiaoxi 163.com> writes:
On Wednesday, 2 April 2014 at 22:33:21 UTC, bearophile wrote:
 Walter Bright:

 Here's Andrei's proposal:

    extern (C++) template nspace() {
        int foo();
    }

I suggest to brainstorm the syntax some more time, because someone could be able to invent a better syntax. Some seeds: extern (C++(nspace)) { int foo(); } extern (C++) struct nspace { int foo(); } extern (C++)(nspace) { int foo(); } extern (C++ nspace) { int foo(); } Bye, bearophile

extern (C++) module nspace;
Apr 02 2014
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Xiaoxi:

 extern (C++) module nspace;

They plan to add some kind of modules to C++ in few years :-( So this risks semantic clashes. Bye, bearophile
Apr 02 2014
prev sibling next sibling parent reply "Mike" <none none.com> writes:
On Wednesday, 2 April 2014 at 22:06:53 UTC, 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.

Walter, some on this list have not been around long enough to understand the motivation for this. Could you please summarize the problem and how this addresses it? Is this for interfacing D to C++, or a way to bring namespace semantics to D? Mike
Apr 02 2014
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/2/2014 4:04 PM, Mike wrote:
 Walter, some on this list have not been around long enough to understand the
 motivation for this.  Could you please summarize the problem and how this
 addresses it? Is this for interfacing D to C++, or a way to bring namespace
 semantics to D?

See the earlier thread entitled: "C++ interface." started yesterday.
Apr 02 2014
prev sibling next sibling parent "Rikki Cattermole" <alphaglosined gmail.com> writes:
On Wednesday, 2 April 2014 at 22:33:21 UTC, bearophile wrote:
 Walter Bright:

 Here's Andrei's proposal:

    extern (C++) template nspace() {
        int foo();
    }

I suggest to brainstorm the syntax some more time, because someone could be able to invent a better syntax. Some seeds:

 extern (C++)(nspace) {
     int foo();
 }

 extern (C++ nspace) {
     int foo();
 }

 Bye,
 bearophile

I definitely like the last two. Small and to the point. But where nspace is a wrapper 'static struct' essentially. So: nspace.foo()
Apr 02 2014
prev sibling next sibling parent "Mike" <none none.com> writes:
On Wednesday, 2 April 2014 at 23:04:58 UTC, Mike wrote:
 On Wednesday, 2 April 2014 at 22:06:53 UTC, Walter Bright wrote:
 Here's Andrei's proposal:

    extern (C++) template nspace() {
        int foo();
    }

semantics to D?

Well, I'm assuming this is specifically for interfacing D with C++ given the 'extern (C++)' attribution. In that case, I think the proposal abuses the 'template' keyword for something that's not really a template. In that case, I find the syntax proposed by bearophile to be far better... extern (C++ nspace) { int foo(); } ...although I would even prefer it be even more explicit... extern (C++ namespace nspace) { int foo(); } I'd also be interested in hearing the arguments against the UDAs and pragmas proposed in the following two links: * https://d.puremagic.com/issues/show_bug.cgi?id=7961 * https://github.com/D-Programming-Language/dmd/pull/2767 The pragma is especially nice since this isn't really a D thing, although bearophile's proposed syntax is hard to argue against. Mike
Apr 02 2014
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Walter Bright:

 I considered that, but it fails because:

 C++:

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

 D:

   extern (C++, S.T) {
       int foo();
       extern (C++, U) {
         int foo();
       }
   }
   foo();  // error, ambiguous, which one?
   S.T.foo(); // S undefined

Then is the idea of "extern(C++) module" by Xiaoxi usable in some way? Bye, bearophile
Apr 02 2014
prev sibling next sibling parent "monnoroch" <monnoroch gmail.com> writes:
On Thursday, 3 April 2014 at 01:06:25 UTC, Walter Bright wrote:
 Because C++ mangles static member functions of structs 
 differently from members of namespaces.

What i meant is not static functions and members of a struct, but a static struct as a concept of a struct, whith can only contain a static stuff. C++ has no such concept, but essentually static struct === namespace. Consider this: extern(C++) static struct A { static struct B { struct X {} int foo(X); } } A.B.foo(A.B.X());
Apr 02 2014
prev sibling next sibling parent "monnoroch" <monnoroch gmail.com> writes:
Also, D already has scope classes, so why not create full 
featured class bindings?

Suppose, i have this:

class A {
private:
     int x;

public:
     A(int x_) : x(x_) {}
     A(const A& v) : x(v.x) {}
     ~A() {}
};

Why not interfase those as:

extern (C++) {
     struct A {
         int x;
         this(int x_); // call c++ A::A(int)
         this(this);   // call c++ A::A(const A&)
         ~this();      // call c++ A::~A()
     }
}


I mean, methods in c++ are just like functions in namespaces with 
first T* argument, so this is also just mangling problem; and all 
those constructors and destructors are not something special 
either.

What stops to do that?
If value semantics isn't appropriate, user, who writes D 
interface can just do it in scope class.
Maby discussing that would also do some good.
Apr 02 2014
prev sibling next sibling parent "monnoroch" <monnoroch gmail.com> writes:
Or even the simplier way. Just do:

extern(C++) struct A {
     int x;
     A A(int x_);
     A A(ref const(A) v);
     void ~A(A*);
}

And call those methods manually:

A obj = A.A(1);
A obj1 = A.A(obj);
A.~A(&obj);
A.~A(&obj1);

The problem here it to distinguish real static methods from fake 
ones. But we can actually make user mark real static methods as 
static.
Apr 02 2014
prev sibling next sibling parent "Kagamin" <spam here.lot> writes:
On Wednesday, 2 April 2014 at 22:06:53 UTC, Walter Bright wrote:
 Here's Andrei's proposal:

     extern (C++) template nspace() {
         int foo();
     }

namespace("nspace") extern (C++) { int 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.

If we have partial C++ bindings, why not have partial template bindings with a subset of features already existing in D? With that you would only need to implement mangling and linking. An interesting and simple enough use case is casting: extern(C++) T my_cast(T,U)(U); extern(C++) interface A{} extern(C++) interface B:A{} A a; B b = my_cast!B(a);
Apr 02 2014
prev sibling next sibling parent "Kagamin" <spam here.lot> writes:
On Wednesday, 2 April 2014 at 22:06:53 UTC, Walter Bright wrote:
 A possible enhancement would be to allow (for all templates 
 with no parameters):

     nspace.foo();

std.string - does it refer to phobos module or C++ string?
Apr 02 2014
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
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?
Apr 03 2014
prev sibling next sibling parent Daniel =?ISO-8859-2?B?S2964Ws=?= <kozzi11 gmail.com> writes:
V Thu, 3 Apr 2014 06:36:54 -0400
Michel Fortin <michel.fortin michelf.ca> napsno:

 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
Apr 03 2014
prev sibling next sibling parent reply "Daniel Murphy" <yebbliesnospam gmail.com> writes:
"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.
Apr 03 2014
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 4/3/14, 4:19 AM, Daniel Murphy wrote:
 "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?

I don't quite see how one is ugly and complicated and the other is... pretty and simple? Anyhow de gustibus.
 Adding syntax for actual namespaces to D is a different beast and IMO
 not worthwhile.

Agreed. Andrei
Apr 03 2014
next sibling parent "Daniel Murphy" <yebbliesnospam gmail.com> writes:
"Andrei Alexandrescu"  wrote in message 
news:lhkebg$1i1p$1 digitalmars.com...

      extern (C++) template nspace() {
          int foo();
      }

This is really ugly and complicated.

 I don't quite see how one is ugly and complicated and the other is... 
 pretty and simple? Anyhow de gustibus.

Stuff inside the template will only be instantiated when used. That's fine when it's just a prototype of a C++ function to be called from D, but much less useful when the implementation is in D and the use is from C++. It can conflict with the eponymous template syntax - D would not be able to tell the difference between a templated function and a function inside a namespace with the same name. It forces this organisation for all symbols that use C++ namespaces. If you define functions in the same namespace in different modules the template symbols will conflict and you will have to use fully-qualified names. On the other side, in D modules are used for symbol organisation. It's powerful enough that you can get namespace::function to match library.module.function (and I expect you can force use of the namespace through clever use of static renamed imports). The missing part is getting the mangling right, and a pragma is the least intrusive way I can imagine to do that.
Apr 03 2014
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 04/03/2014 09:55 PM, Andrei Alexandrescu wrote:
 ...
 Anyhow de gustibus.

There's good and bad taste.
Apr 05 2014
prev sibling next sibling parent =?UTF-8?B?IlRow6lv?= Bueno" <munrek gmx.com> writes:
On Thursday, 3 April 2014 at 11:19:53 UTC, Daniel Murphy wrote:
 "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.

IMO I don't think pragmas are meant to this kind of uses, extern(C++) already exists and makes more sense.
Apr 03 2014
prev sibling next sibling parent reply "Mason McGill" <mmcgill caltech.edu> writes:
"Walter Bright"  wrote in message 
news:lhi1lt$269h$1 digitalmars.com...
 Here's Andrei's proposal:

     extern (C++) template nspace() {
         int foo();
     }

- An "extern (C++)" function lets you use a C++ function. - An "extern (C++)" interface lets you use a C++ interface (declared as a class, as is always the case in C++). - An "extern (C++)" template lets you use a C++... namespace? On Thursday, 3 April 2014 at 11:19:53 UTC, Daniel Murphy wrote:
 Why not just

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

one), and seems to be a rather harmless addition to the language. It also fulfills the goal of allowing access to C++ libraries without cluttering D with C++ language features. I don't want to have to explain to my students the difference between "modules" "D templates" and "C++ namespace templates" (it reminds me of old- and new-style classes in Python 2).
Apr 03 2014
parent David Gileadi <gileadis NSPMgmail.com> writes:
On 4/3/14, 11:59 PM, Mason McGill wrote:
 "Walter Bright"  wrote in message news:lhi1lt$269h$1 digitalmars.com...
 Here's Andrei's proposal:

     extern (C++) template nspace() {
         int foo();
     }

- An "extern (C++)" function lets you use a C++ function. - An "extern (C++)" interface lets you use a C++ interface (declared as a class, as is always the case in C++). - An "extern (C++)" template lets you use a C++... namespace? On Thursday, 3 April 2014 at 11:19:53 UTC, Daniel Murphy wrote:
 Why not just

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

seems to be a rather harmless addition to the language. It also fulfills the goal of allowing access to C++ libraries without cluttering D with C++ language features. I don't want to have to explain to my students the difference between "modules" "D templates" and "C++ namespace templates" (it reminds me of old- and new-style classes in Python 2).

The above well describes my first reaction to the syntax (except the part about having students). And my second reaction too, in fact.
Apr 04 2014
prev sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
Not that I ever do this, but I think you need to deal with this 
C++ construct:

namespace exposed_ns {
   using namespace internal_ns_2134zxdssdffrandomblablah;
   using namespace internal_ns_2634zasdsfsdrandomblablah;
   using namespace internal_ns_2993adsfadsfrandomblablah;
}

To do this in D you would have to be able to set up a search 
sequence as an alias somehow.
Apr 05 2014
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
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
Apr 03 2014
parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
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.
Apr 03 2014
prev sibling next sibling parent "Robert Clipsham" <robert octarineparrot.com> writes:
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
Apr 03 2014
prev sibling next sibling parent "Daniel Kozak" <kozzi11 gmail.com> writes:
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 :)
Apr 03 2014
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Apr 03, 2014 at 12:43:59PM -0700, Walter Bright wrote:
 On 4/3/2014 4:06 AM, Daniel Kozk 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!

The current situation where module/scope qualifiers clash with UFCS sux, though. static import std.algorithm; ... auto myRange = ...; //myRange.std.algorithm.find(...); // NG :-( alias find = std.algorithm.find; myRange.find(...); // OK But this is kinda tangential to this topic. :P T -- My program has no bugs! Only undocumented features...
Apr 03 2014
prev sibling next sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Wednesday, 2 April 2014 at 22:06:53 UTC, 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'm not familiar with usual C++ mangling as much as D. Are template and namespace mangled the same way ?
Apr 03 2014
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/3/2014 5:47 PM, deadalnix wrote:
 I'm not familiar with usual C++ mangling as much as D. Are
 template and namespace mangled the same way ?

No.
Apr 04 2014
prev sibling next sibling parent reply "Dicebot" <public dicebot.lv> writes:
Late to the thread, my short opinion:

extern(C++ namespace::path) looks best. It should only affect 
mangling and have no impact on fully qualified name on D side. 
Most KISS solution I have read in the thread.
Apr 04 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/4/2014 5:34 AM, Dicebot wrote:
 Late to the thread, my short opinion:

 extern(C++ namespace::path) looks best. It should only affect mangling and have
 no impact on fully qualified name on D side. Most KISS solution I have read in
 the thread.

Fails because: C++: namespace S { namespace T { int foo(); namespace U { int foo(); } } } D: extern (C++, S::T) { int foo(); extern (C++, U) { int foo(); } } foo(); // error, ambiguous, which one? S.T.foo(); // S undefined
Apr 04 2014
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/4/2014 1:00 PM, "Ola Fosheim Grøstad" 
<ola.fosheim.grostad+dlang gmail.com>" wrote:
 I want explicit namespaces "S::T::foo()".

We already have a scope operator, '.', don't need another one.
Apr 04 2014
prev sibling next sibling parent "Mason McGill" <mmcgill caltech.edu> writes:
On Friday, 4 April 2014 at 12:34:15 UTC, Dicebot wrote:
 Late to the thread, my short opinion:

 extern(C++ namespace::path) looks best. It should only affect 
 mangling and have no impact on fully qualified name on D side. 
 Most KISS solution I have read in the thread.

I actually remember almost trying this syntax before reading this thread. It's definitely intuitive, and it KIS. Though, may I suggest extern(C++, namespace::path) or extern(C++, namespace, path) keeping in line with __traits and pragma?
Apr 04 2014
prev sibling next sibling parent reply =?UTF-8?B?U2ltZW4gS2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On 03.04.2014 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 have to say I like Robert Clipsham's idea best: extern(C++) module nspace { int foo(); // Is this also extern(C++)? I think it should be. } extern(C++) module nspace { module innernspace { int bar(); // Also extern(C++), if we follow the example above. } } I haven't the foggiest idea how C++ modules are supposed to work, so there might be clashes with those somehow? -- Simen
Apr 04 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/5/2014 8:24 AM, Dicebot wrote:
 This is very practical thing. By introducing special constructs to support some
 foreign language you open the can of worms. Where does one stop? Should we also
 expect adding some new idioms for better JNI support? Or Python? I can't see
any
 reason why C++ has to be any special and you can't nicely support them all. We
 don't even truly do this for C and this the only real ABI standard.

A very good question. Some points to consider: 1. D is supposed to be a practical language, and be designed to get s**t done. 2. D has long recognized that C++ exists and tries to be accommodating - with extern(C++) and C++ compatible COM classes. extern(C++) already does more than just adjust the name mangling. 3. There's significant demand for supporting C++ namespaces among people trying to migrate to D. There's more than just the people who post here. Currently, this is a barrier to adoption of D, and an unnecessary one. 4. I know I very much appreciate products that don't try and pretend they are the shiznit and nothing else exists. For example, Thunderbird Mail was able to import my old Outlook Express database perfectly, enabling me to completely abandon OE. 5. There's also work underway to better integrate with ObjectiveC. In the light of that: 1. We cannot nicely support them all. But we don't have to. We can support the low hanging fruit. 2. C++ namespaces are very low hanging fruit, with a significant payoff. It's worthwhile. 3. C++ is special because a) we can support limited interoperability without much effort and b) a lot of people come to D from C++ and want to interoperate.
Apr 05 2014
parent Jacob Carlborg <doob me.com> writes:
On 2014-04-05 22:42, Walter Bright wrote:

 2. C++ namespaces are very low hanging fruit, with a significant payoff.
 It's worthwhile.

I think it's very low hanging fruit to add support for basic C++ namespaces. Support for basically just set the mangled name in a somewhat nice way, a pragma for example. If we're talking about adding something more advanced like "::" or "extern (C++) template" which my affect the current name look up rules then I don't think that's so low hanging fruit anymore. -- /Jacob Carlborg
Apr 06 2014
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Friday, 4 April 2014 at 18:51:21 UTC, Simen Kjærås wrote:
 I have to say I like Robert Clipsham's idea best:

 extern(C++) module nspace {
     int foo(); // Is this also extern(C++)? I think it should 
 be.
 }

 extern(C++) module nspace {
     module innernspace {
         int bar(); // Also extern(C++), if we follow the 
 example above.
     }
 }

All solutions based on binding extern(C++) to some D qualification entity are bad because they confuse reader into thinking that `bar` is actually `nspace.innerspace.bar` and that should never happen.
Apr 04 2014
prev sibling next sibling parent =?UTF-8?B?U2ltZW4gS2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On 04.04.2014 20:54, Dicebot wrote:
 On Friday, 4 April 2014 at 18:51:21 UTC, Simen Kjærås wrote:
 I have to say I like Robert Clipsham's idea best:

 extern(C++) module nspace {
     int foo(); // Is this also extern(C++)? I think it should be.
 }

 extern(C++) module nspace {
     module innernspace {
         int bar(); // Also extern(C++), if we follow the example above.
     }
 }

All solutions based on binding extern(C++) to some D qualification entity are bad because they confuse reader into thinking that `bar` is actually `nspace.innerspace.bar` and that should never happen.

I'm not entirely sure I follow you here. Is this what you mean? extern(C++) module nspace { int foo(); } void main() { foo(); // Either this does not work, (#1) nspace.foo(); // or this does not work. (#2) } If so, is that really bad? I'd say the better choice is to make #2 work, as then #1 can be made to work with a simple alias: alias foo = nspace.foo; If I'm far off into the fields of ignorance now, care to show me the way to a better understanding? -- Simen
Apr 04 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Friday, 4 April 2014 at 19:43:56 UTC, Walter Bright wrote:
   foo();  // error, ambiguous, which one?
   S.T.foo(); // S undefined

I want explicit namespaces "S::T::foo()".
Apr 04 2014
prev sibling next sibling parent "Tove" <tove fransson.se> writes:
On Friday, 4 April 2014 at 19:43:56 UTC, Walter Bright wrote:
 C++:

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

 D:

   extern (C++, S::T) {
       int foo();
       extern (C++, U) {
         int foo();
       }
   }
   foo();  // error, ambiguous, which one?
   S.T.foo(); // S undefined

Why would we need new ways of declaring scopes in D? Overriding the external mangling should be sufficient? If there are collisions you can use any type of scope you prefer to avoid the issue, modules, structs, templates, even functions or blocks... void fun1() { extern (C++, S::T) int foo();} void fun2() { extern (C++, S::T::U) int foo();} extern (C++, S::T::U) int foo(); struct test { extern (C++, S::T) int foo();}
Apr 04 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Friday, 4 April 2014 at 20:06:49 UTC, Walter Bright wrote:
 We already have a scope operator, '.', don't need another one.

It is more clear to the reader that it is an external namespace and you avoid renaming because then C++ has it's own namespace in D reducing the chances of clashes. But it's a minor issue, although I think it is important for long term maintainability of code to easily discriminate between C++ function calls (which tend to be supportive lower level libraries/engines) and D function calls (which tend to be higher level code). When you do contract work on many projects for different small businesses, you often get requests for modifications/additions 1-2 times a year or so. The less chance of code misinterpretation, the better.
Apr 04 2014
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Tove:

 Why would we need new ways of declaring scopes in D? Overriding 
 the external mangling should be sufficient? If there are 
 collisions you can use any type of scope you prefer to avoid 
 the issue, modules, structs, templates, even functions or 
 blocks...

 void fun1() { extern (C++, S::T) int foo();}
 void fun2() { extern (C++, S::T::U) int foo();}

 extern (C++, S::T::U) int foo();
 struct test { extern (C++, S::T) int foo();}

This seems promising, but this idea needs to become simpler. Bye, bearophile
Apr 04 2014
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Friday, 4 April 2014 at 19:43:56 UTC, Walter Bright wrote:
 Fails because:

 C++:

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

 D:

   extern (C++, S::T) {
       int foo();
       extern (C++, U) {
         int foo();
       }
   }
   foo();  // error, ambiguous, which one?
   S.T.foo(); // S undefined

I don't feel this is a problem. Such foo's should be disambugated by D tools, which means using different modules. Exact matching between C++ and D sources is impossible anyway, it is not worth complicating D qualification system for that.
Apr 04 2014
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Friday, 4 April 2014 at 19:33:34 UTC, Simen Kjærås wrote:
 I'm not entirely sure I follow you here. Is this what you mean?

 extern(C++) module nspace {
     int foo();
 }

 void main() {
     foo();        // Either this does not work, (#1)
     nspace.foo(); // or this does not work.     (#2)
 }

 If so, is that really bad? I'd say the better choice is to make 
 #2 work, as then #1 can be made to work with a simple alias:

 alias foo = nspace.foo;

 If I'm far off into the fields of ignorance now, care to show 
 me the way to a better understanding?

#2 should not compile. D currently does not have any notion of namespaces other than modules / aggregates and I am against introducing those just for the sake of interfacing with C++.
Apr 04 2014
prev sibling next sibling parent "Mason McGill" <mmcgill caltech.edu> writes:
On Friday, 4 April 2014 at 21:39:01 UTC, bearophile wrote:
 Tove:

 Why would we need new ways of declaring scopes in D? 
 Overriding the external mangling should be sufficient? If 
 there are collisions you can use any type of scope you prefer 
 to avoid the issue, modules, structs, templates, even 
 functions or blocks...

 void fun1() { extern (C++, S::T) int foo();}
 void fun2() { extern (C++, S::T::U) int foo();}

 extern (C++, S::T::U) int foo();
 struct test { extern (C++, S::T) int foo();}

This seems promising, but this idea needs to become simpler. Bye, bearophile

This seems like it would be simple if it came with a recommended style for library wrappers, e.g. // C++ namespace A { namespace B { void f1(); void f2(); } namespace C { void f3(); void f4(); } } // D struct A { struct B { extern(C++, A, B): static void f1(); static void f2(); } struct C { extern(C++, A, C): static void f3(); static void f4(); } } This can be easily generated by hand or with something like SWIG, and keeps the semantics of "extern" consistent throughout the language (it still only affects the ABI). This also keeps things simple for users who just want to call one function. // D void callF1() { extern(C++, A, B) void f1(); f1(); } I used "," instead of "::" because it avoids adding a new token, but that's more of an aesthetic issue.
Apr 04 2014
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Friday, 4 April 2014 at 07:06:30 UTC, Walter Bright wrote:
 On 4/3/2014 5:47 PM, deadalnix wrote:
 I'm not familiar with usual C++ mangling as much as D. Are
 template and namespace mangled the same way ?

No.

Then that is a bad idea.
Apr 04 2014
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Friday, 4 April 2014 at 22:17:45 UTC, Dicebot wrote:
 On Friday, 4 April 2014 at 19:33:34 UTC, Simen Kjærås wrote:
 I'm not entirely sure I follow you here. Is this what you mean?

 extern(C++) module nspace {
    int foo();
 }

 void main() {
    foo();        // Either this does not work, (#1)
    nspace.foo(); // or this does not work.     (#2)
 }

 If so, is that really bad? I'd say the better choice is to 
 make #2 work, as then #1 can be made to work with a simple 
 alias:

 alias foo = nspace.foo;

 If I'm far off into the fields of ignorance now, care to show 
 me the way to a better understanding?

#2 should not compile. D currently does not have any notion of namespaces other than modules / aggregates and I am against introducing those just for the sake of interfacing with C++.

templates, function bodies, block statements, ...
Apr 04 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Friday, 4 April 2014 at 22:17:45 UTC, Dicebot wrote:
 #2 should not compile. D currently does not have any notion of 
 namespaces other than modules / aggregates and I am against 
 introducing those just for the sake of interfacing with C++.

If you want to interface with C++ you should do it well or not at all. In C++ namespace names reside in their own namespace which means that you get short names like "std", "qt" etc. Which in turn means you have to rename those to "CPPstd", "CPPqt" etc in D in order to disambiguate the symbols. Having a dedicated namespace operator would be a lot more convenient.
Apr 05 2014
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Saturday, 5 April 2014 at 08:42:27 UTC, Ola Fosheim Grøstad 
wrote:
 On Friday, 4 April 2014 at 22:17:45 UTC, Dicebot wrote:
 #2 should not compile. D currently does not have any notion of 
 namespaces other than modules / aggregates and I am against 
 introducing those just for the sake of interfacing with C++.

If you want to interface with C++ you should do it well or not at all. In C++ namespace names reside in their own namespace which means that you get short names like "std", "qt" etc. Which in turn means you have to rename those to "CPPstd", "CPPqt" etc in D in order to disambiguate the symbols. Having a dedicated namespace operator would be a lot more convenient.

D has own tools to disambugate symbols. Introducing new ones is equivalent to admitting D module system does not work by design.
Apr 05 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Saturday, 5 April 2014 at 12:07:36 UTC, Dicebot wrote:
 D has own tools to disambugate symbols. Introducing new ones is 
 equivalent to admitting D module system does not work by design.

I think it is primarily a notation issue. Should the notation help you discern what is C++ and what is D, or do you have to memorize symbols? How much extra notational work is it acceptable to impose on the programmer? There are advantages and disadvantages to both approaches. Pro explicit c++ namespaces: - Easy to discern what is C++ and what is D. - Less chance of future irreconcilable design conflicts when either C++ or D changes (e.g. C++18 and beyond) - Having a philosophy of "native foreign functions" rather than "masquerading as D constructs" makes it easier to integrate with other languages beyond c/c++ at a later stage. Con: - More syntax to understand for newbies - Requires a little bit more refactoring when moving C++ code to D.
Apr 05 2014
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Saturday, 5 April 2014 at 12:30:28 UTC, Ola Fosheim Grøstad 
wrote:
 Should the notation help you discern what is C++ and what is D, 
 or do you have to memorize symbols? How much extra notational 
 work is it acceptable to impose on the programmer?

It shouldn't. The fact how entity is exposed via some external binary interface should not have any notable impact on D side of things (unless you dwell into ABI realm). This is exactly what "extern" is for - matching symbols from domain of D terms to some external alien domain.
Apr 05 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Saturday, 5 April 2014 at 12:58:54 UTC, Dicebot wrote:
 It shouldn't. The fact how entity is exposed via some external 
 binary interface should not have any notable impact on D side 
 of things (unless you dwell into ABI realm).

This is a design philosophical issue, you can make it normative if you want, but only if it is consistent with the overall design philosophy. Working on making that philosophy explicit is important, D2 is showing some signs of having gone through a lot of evolutionary design and IMHO signs of a need for notational redesign. Meaning: recreate the syntax to fit the desired semantics that the language has obtained over time (as in designing it, not evolving). Not distinguishing between C++/D does however have consequences: if foreign constructs have the same appearance as the language constructs then you should also make sure that all the semantics are the same. E.g. C++ exceptions, calls to C++ new etc have to be fully harmonized with D equivalents.
Apr 05 2014
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Saturday, 5 April 2014 at 13:11:27 UTC, Ola Fosheim Grøstad 
wrote:
 On Saturday, 5 April 2014 at 12:58:54 UTC, Dicebot wrote:
 It shouldn't. The fact how entity is exposed via some external 
 binary interface should not have any notable impact on D side 
 of things (unless you dwell into ABI realm).

This is a design philosophical issue, you can make it normative if you want, but only if it is consistent with the overall design philosophy.

This is very practical thing. By introducing special constructs to support some foreign language you open the can of worms. Where does one stop? Should we also expect adding some new idioms for better JNI support? Or Python? I can't see any reason why C++ has to be any special and you can't nicely support them all. We don't even truly do this for C and this the only real ABI standard.
Apr 05 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Saturday, 5 April 2014 at 15:24:32 UTC, Dicebot wrote:
 This is very practical thing. By introducing special constructs 
 to support some foreign language you open the can of worms.

Yep, but I believe C++ is increasingly going to replace C as a language for writing basic libraries and engines in the next few decades. Which isn't great for interop, but a trend still.
Apr 05 2014
prev sibling next sibling parent "Mason McGill" <mmcgill caltech.edu> writes:
On Saturday, 5 April 2014 at 15:24:32 UTC, Dicebot wrote:
 This is very practical thing. By introducing special constructs 
 to support some foreign language you open the can of worms. 
 Where does one stop? Should we also expect adding some new 
 idioms for better JNI support? Or Python? I can't see any 
 reason why C++ has to be any special and you can't nicely 
 support them all. We don't even truly do this for C and this 
 the only real ABI standard.

Another way to put this is that D is its own language, not a C++ extension. IMO, an FFI should make interoperability possible via ABI matching, but it should not compromise the language (by making its scoping rules more complicated, introducing redundant constructs, or introducing a new token ("::") that could be used for another feature).
Apr 05 2014
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/2/2014 3:07 PM, Walter Bright wrote:
 One downside of this proposal is that if we ever (perish the thought!)
attempted
 to interface to C++ templates, this design would preclude that.

Yes, this seems to be a fatal flaw. Another design that has evolved from these discussions and my discussions with Andrei on it: extern (C++, namespace = A.B) { void foo(); void bar(); } extern (C++, namespace = C) void foo(); bar(); // works A.B.bar(); // works foo(); // error: ambiguous C.foo(); // works alias C.foo foo; foo(); // works, calling C.foo() I really think the namespace semantics should be attached to the extern(C++) rather than be a separate pragma. Having the namespace= thing means that namespace isn't a keyword, and provides a general mechanism where we can add language specific information as necessary.
Apr 05 2014
next sibling parent reply "Tove" <tove fransson.se> writes:
On Saturday, 5 April 2014 at 20:47:29 UTC, Walter Bright wrote:
 On 4/2/2014 3:07 PM, Walter Bright wrote:
 One downside of this proposal is that if we ever (perish the 
 thought!) attempted
 to interface to C++ templates, this design would preclude that.

Yes, this seems to be a fatal flaw. Another design that has evolved from these discussions and my discussions with Andrei on it: extern (C++, namespace = A.B) { void foo(); void bar(); } extern (C++, namespace = C) void foo(); bar(); // works A.B.bar(); // works foo(); // error: ambiguous C.foo(); // works alias C.foo foo; foo(); // works, calling C.foo() I really think the namespace semantics should be attached to the extern(C++) rather than be a separate pragma. Having the namespace= thing means that namespace isn't a keyword, and provides a general mechanism where we can add language specific information as necessary.

How could this common pattern look? std::string boost::fun(std::string arg) alias cpp = extern (C++, namespace = std); alias boost = extern (C++, namespace = boost); cpp.string boost.fun(cpp.string arg) ?
Apr 05 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/5/2014 2:31 PM, Tove wrote:
 How could this common pattern look?
 std::string
 boost::fun(std::string arg)

 alias cpp    = extern (C++, namespace = std);
 alias boost = extern (C++, namespace = boost);

 cpp.string
 boost.fun(cpp.string arg)

 ?

extern (C++, namespace = std) { struct string { ... } } extern (C++, namespace = boost) { void fun(std.string arg); }
Apr 05 2014
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/6/2014 2:56 AM, "Marc Schütz" <schuetzm gmx.net>" wrote:
 And wouldn't it clash with D's std package?

Yes. But D has numerous methods of disambiguation.
Apr 06 2014
prev sibling next sibling parent reply Michel Fortin <michel.fortin michelf.ca> writes:
On 2014-04-05 20:47:32 +0000, Walter Bright <newshound2 digitalmars.com> said:

 On 4/2/2014 3:07 PM, Walter Bright wrote:
 One downside of this proposal is that if we ever (perish the thought!) 
 attempted
 to interface to C++ templates, this design would preclude that.

Yes, this seems to be a fatal flaw. Another design that has evolved from these discussions and my discussions with Andrei on it: extern (C++, namespace = A.B) { void foo(); void bar(); } extern (C++, namespace = C) void foo(); bar(); // works A.B.bar(); // works foo(); // error: ambiguous C.foo(); // works alias C.foo foo; foo(); // works, calling C.foo() I really think the namespace semantics should be attached to the extern(C++) rather than be a separate pragma. Having the namespace= thing means that namespace isn't a keyword, and provides a general mechanism where we can add language specific information as necessary.

I like this idea. But... should this potentially useful thing really be restricted to extern C++ things? I've seen at least one attempt to create a namespace using what D currently offers [1], and frankly something like the above would make much more sense than a class no one can instantiate. [1]: http://dlang.org/phobos/std_datetime.html#.Clock Here's a suggestion: namespace A.B { // can create two levels at once, yeah! void foo(); void bar(); } namespace C { void foo(); } Make those C++ declarations, it does not look too foreign anymore: extern (C++) namespace A.B { void foo(); void bar(); } extern (C++) namespace C { void foo(); } -- Michel Fortin michel.fortin michelf.ca http://michelf.ca
Apr 05 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/5/2014 2:55 PM, Michel Fortin wrote:
 I like this idea. But... should this potentially useful thing really be
 restricted to extern C++ things? I've seen at least one attempt to create a
 namespace using what D currently offers [1], and frankly something like the
 above would make much more sense than a class no one can instantiate.

I can't escape the feeling that if you're trying to do namespaces in D, you're doing something worng. I feel that C++ messed up namespace design because: 1. namespaces are not closed 2. they have no relationship with modules which has wound up forcing the addition of Yet Another Design when imports and modules are added to C++.
Apr 05 2014
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/6/2014 12:39 PM, "Ola Fosheim Grøstad" 
<ola.fosheim.grostad+dlang gmail.com>" wrote:
 On Saturday, 5 April 2014 at 23:26:30 UTC, Walter Bright wrote:
 I feel that C++ messed up namespace design because:

 1. namespaces are not closed
 2. they have no relationship with modules

Namespaces are not as powerful as they could have been, but being able to add symbols to an external scope (like classes) is very useful if done right (e.g. cross-cutting enhancements, adding members to external classes like "saveyourself", "printyourself").

It's seriously wrong to allow such. It makes a larger code base nearly impossible to reliably reason about, leading one to rely on conventions like "don't add stuff to namespaces". D has closed scopes, and members can be "added" to external classes just fine, using CTFE.
Apr 06 2014
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/6/2014 2:00 PM, monarch_dodra wrote:
 On Sunday, 6 April 2014 at 20:17:09 UTC, Walter Bright wrote:
 D has closed scopes, and members can be "added" to external classes just fine,
 using CTFE.

You mean UFCS?

Yes, my mistake.
 As in, for example, "front" for arrays? It doesn't work as well
 as advertised though. The issue is that the added members are only visible if
 the *called* code knows to import the *caller* code.

That's a feature of a modular system, not a bug. D does not have a global name space, on purpose.
 This breaks as soon as you
 leave your own internal ecosystem.

 //----
 import a;
 
 struct S //Some object
 {
 }

 //Extend to make it a range.
 bool empty(S);
 int front(S);
 void popFront(S);

 //Try it.
 void main()
 {
      S s;
      foreach(e; s) //Error: invalid foreach aggregate s
          writeln(s);
      s.array(); //Error: template std.range.take cannot...
      a.foo(s); //Error: no property 'popFront' for type 'S'
 }
 //----
 module a;

 void foo(T)(T t)
 {
      t.popFront();
 }
 //----
 Well that horribly fails.

That's based on a misunderstanding of how scoped lookup works in D, and how to use it properly. In the particular instance above, there is simply no reason to not put front() as a member of S, since they are in the same module.
 Because when calling a template, you are only importing the passed argument,
but
 not his ecosystem with it. The only way in D to "really" extend an existing
 object, is to wrap it into a new object. And even then, the wrapping is
limited,
 because you can't orthogonally wrap (eg the wrapping linearly stacks, whereas
 UCFS *could* add two completely independent functionalities). Not to mention
 issues with code bloat...

You're right in that if you try to do things the C++ way in D, things won't work out so well. D can do all these things, but they are done in a different way - a way that is much more robust. The fault in the C++ method of extending namespaces is that two independently developed modules had better not extend the same namespace with the same names. You will not necessarily get a compiler error from violating this - code may just wind up calling the wrong overload. I.e. it does not scale.
 C++'s namespaces have their flaws, but they *are* scalable in a way D's modules
 aren't, thanks to Koenig Lookup.

I've never seen anyone defend Koenig lookup as anything but a hack before :-)
Apr 06 2014
prev sibling parent Michel Fortin <michel.fortin michelf.ca> writes:
On 2014-04-06 19:39:31 +0000, "Ola Fosheim Grstad" 
<ola.fosheim.grostad+dlang gmail.com> said:

 Unfortunately that seems to be years into the future? Although clang 
 has begun implementing something:
 
 http://clang.llvm.org/docs/Modules.html
 
 I've got at feeling that if clang gets something working it will become 
 a de-facto standard due to demand.

Modules are already in use on OS X for some system frameworks. It can result in slightly improved compile times. It has been enabled by default for new Xcode projects for some time. With modules enabled, clang interpret #includes as module imports for system frameworks having a module map. It's so transparent you probably won't notice anything has changed. The only thing that really changes with modules is you don't have access to symbols you don't have imported yourself. D already works like that. I think D can ignore those modules, just like it ignores header files. -- Michel Fortin michel.fortin michelf.ca http://michelf.ca
Apr 06 2014
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Michel Fortin:

 Here's a suggestion:

 	 namespace A.B { // can create two levels at once, yeah!
 		void foo();
 		void bar();
 	}
 	 namespace C {
 		void foo();
 	}

 Make those C++ declarations, it does not look too foreign 
 anymore:

 	extern (C++)  namespace A.B {
 		void foo();
 		void bar();
 	}
 	extern (C++)  namespace C {
 		void foo();
 	}

I suggest to keep the access to C++ namespaces as a feature for interoperability only, and to have no namespaces in D. Bye, bearophile
Apr 05 2014
prev sibling next sibling parent reply Michel Fortin <michel.fortin michelf.ca> writes:
On 2014-04-05 20:47:32 +0000, Walter Bright <newshound2 digitalmars.com> said:

 Yes, this seems to be a fatal flaw. Another design that has evolved 
 from these discussions and my discussions with Andrei on it:
 
      extern (C++, namespace = A.B) { void foo(); void bar(); }
      extern (C++, namespace = C) void foo();
 
      bar();  // works
      A.B.bar(); // works
      foo(); // error: ambiguous
      C.foo();   // works
 
      alias C.foo foo;
      foo();  // works, calling C.foo()

What if you also have a C++ foo at global scope? module cpptest; extern (C++) void foo(); extern (C++, namespace = A) void foo(); foo(); // ambiguous A.foo(); // works .foo(); // works? cpptest.foo(); // works? Does these two last lines make sense? -- Michel Fortin michel.fortin michelf.ca http://michelf.ca
Apr 05 2014
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/5/2014 6:26 PM, Michel Fortin wrote:
 What if you also have a C++ foo at global scope?

It'll work exactly the same as import does.
      module cpptest;

      extern (C++) void foo();
      extern (C++, namespace = A) void foo();

      foo(); // ambiguous
      A.foo(); // works
      .foo(); // works?

Yes.
      cpptest.foo(); // works?

Yes.
 Does these two last lines make sense?

Just as much sense as: module bar; void foo(); .foo(); // works bar.foo(); // works Namespace lookup rules would be exactly the same as for imports and mixin templates.
Apr 05 2014
prev sibling next sibling parent "Tove" <tove fransson.se> writes:
On Sunday, 6 April 2014 at 02:33:38 UTC, Walter Bright wrote:
 On 4/5/2014 6:26 PM, Michel Fortin wrote:
 What if you also have a C++ foo at global scope?

It'll work exactly the same as import does.
     module cpptest;

     extern (C++) void foo();
     extern (C++, namespace = A) void foo();

     foo(); // ambiguous
     A.foo(); // works
     .foo(); // works?

Yes.
     cpptest.foo(); // works?

Yes.
 Does these two last lines make sense?

Just as much sense as: module bar; void foo(); .foo(); // works bar.foo(); // works Namespace lookup rules would be exactly the same as for imports and mixin templates.

My main reservation against the new suggestion is that one would be forced to open a new nested namespace even when it's detrimental, because in some cases the namespace structure is already reflected in the filesystem(just like for D:s module system). I can't assess how widespread this is globally, but at least some high-quality projects already have guidelines to use file/namespace mappings. A random example from boost: boost::asio::ip::multicast boost/asio/ip/multicast.hpp One can of course workaround this issue with an extra alias for every imported symbol, or use compile-time reflection to auto-generate all alias statements... (or heaven forbid, put entire boost in one file ;)) I assume the "namespace = xxx" syntax is some sort of named parameter, would it be possible to add another similar param, which only changes mangling and doesn't actually create a new scope?
Apr 06 2014
prev sibling next sibling parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Saturday, 5 April 2014 at 21:43:03 UTC, Walter Bright wrote:
 On 4/5/2014 2:31 PM, Tove wrote:
 How could this common pattern look?
 std::string
 boost::fun(std::string arg)

 alias cpp    = extern (C++, namespace = std);
 alias boost = extern (C++, namespace = boost);

 cpp.string
 boost.fun(cpp.string arg)

 ?

extern (C++, namespace = std) { struct string { ... } } extern (C++, namespace = boost) { void fun(std.string arg); }

What would std be here from D's point of view? A module? Or a new kind of symbol? And wouldn't it clash with D's std package?
Apr 06 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Saturday, 5 April 2014 at 23:26:30 UTC, Walter Bright wrote:
 I feel that C++ messed up namespace design because:

 1. namespaces are not closed
 2. they have no relationship with modules

Namespaces are not as powerful as they could have been, but being able to add symbols to an external scope (like classes) is very useful if done right (e.g. cross-cutting enhancements, adding members to external classes like "saveyourself", "printyourself").
 which has wound up forcing the addition of Yet Another Design 
 when imports and modules are added to C++.

Unfortunately that seems to be years into the future? Although clang has begun implementing something: http://clang.llvm.org/docs/Modules.html I've got at feeling that if clang gets something working it will become a de-facto standard due to demand.
Apr 06 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Sunday, 6 April 2014 at 20:17:09 UTC, Walter Bright wrote:
 It's seriously wrong to allow such. It makes a larger code base 
 nearly impossible to reliably reason about, leading one to rely 
 on conventions like "don't add stuff to namespaces".

Depends on how it is done. For BETA, there was a seperate "fragment system" that allowed AST specified extension points. This system was used for both extensions and for encapsulation/API definition. You basically defined "slots" in the syntax three where code could be injected (following the grammar of the slot) and what should be hidden etc. It was simplistic elegance IMO: http://www.cs.au.dk/~beta/Manuals/latest/beta/fragment.html The weakness was that they didn't allow for dynamic dispatch (required static resolution), but that was an implementation issue, I think.
Apr 06 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
Btw, cross-cutting programming is indeed meant to cater for 
programming in the large:

http://en.wikipedia.org/wiki/Aspect-oriented_programming
Apr 06 2014
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Sunday, 6 April 2014 at 20:17:09 UTC, Walter Bright wrote:
 D has closed scopes, and members can be "added" to external 
 classes just fine, using CTFE.

You mean UFCS? As in, for example, "front" for arrays? It doesn't work as well as advertised though. The issue is that the added members are only visible if the *called* code knows to import the *caller* code. This breaks as soon as you leave your own internal ecosystem. //---- import a;  struct S //Some object { } //Extend to make it a range. bool empty(S); int front(S); void popFront(S); //Try it. void main() { S s; foreach(e; s) //Error: invalid foreach aggregate s writeln(s); s.array(); //Error: template std.range.take cannot... a.foo(s); //Error: no property 'popFront' for type 'S' } //---- module a; void foo(T)(T t) { t.popFront(); } //---- Well that horribly fails. Because when calling a template, you are only importing the passed argument, but not his ecosystem with it. The only way in D to "really" extend an existing object, is to wrap it into a new object. And even then, the wrapping is limited, because you can't orthogonally wrap (eg the wrapping linearly stacks, whereas UCFS *could* add two completely independent functionalities). Not to mention issues with code bloat... C++'s namespaces have their flaws, but they *are* scalable in a way D's modules aren't, thanks to Koenig Lookup.
Apr 06 2014
prev sibling next sibling parent "Adam Wilson" <flyboynw gmail.com> writes:
On Sat, 05 Apr 2014 13:47:32 -0700, Walter Bright  
<newshound2 digitalmars.com> wrote:

 On 4/2/2014 3:07 PM, Walter Bright wrote:
 One downside of this proposal is that if we ever (perish the thought!)  
 attempted
 to interface to C++ templates, this design would preclude that.

Yes, this seems to be a fatal flaw. Another design that has evolved from these discussions and my discussions with Andrei on it: extern (C++, namespace = A.B) { void foo(); void bar(); } extern (C++, namespace = C) void foo(); bar(); // works A.B.bar(); // works foo(); // error: ambiguous C.foo(); // works alias C.foo foo; foo(); // works, calling C.foo() I really think the namespace semantics should be attached to the extern(C++) rather than be a separate pragma. Having the namespace= thing means that namespace isn't a keyword, and provides a general mechanism where we can add language specific information as necessary.

This seems like a reasonable way to interop with C++ namespace in a D way. I also think that it is something that we should do ASAP. I know that for Aurora, I will not be able to add complete DirectX support until the C++ namespace interop problem is solved. Specifically because the highly optimized DirectXMath functions are inside a namespace. I do not consider pre-mangling a solution, it's a hack for something that is quite common in C++, and it's fragile. -- Adam Wilson GitHub/IRC: LightBender Aurora Project Coordinator
Apr 07 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Monday, 7 April 2014 at 01:35:37 UTC, Michel Fortin wrote:
 Modules are already in use on OS X for some system frameworks. 
 It can result in slightly improved compile times. It has been 
 enabled by default for new Xcode projects for some time.

Thanks for sharing, I wasn't aware of that. That means that clang will make this a priority. But I guess clang is a long way from not having end users write their own header files still.
Apr 07 2014
prev sibling next sibling parent "Paulo Pinto" <pjmlp progtools.org> writes:
On Monday, 7 April 2014 at 08:06:11 UTC, Ola Fosheim Grøstad 
wrote:
 On Monday, 7 April 2014 at 01:35:37 UTC, Michel Fortin wrote:
 Modules are already in use on OS X for some system frameworks. 
 It can result in slightly improved compile times. It has been 
 enabled by default for new Xcode projects for some time.

Thanks for sharing, I wasn't aware of that. That means that clang will make this a priority. But I guess clang is a long way from not having end users write their own header files still.

clang developers are the ones driving the ISO C++ Modules working group, so whatever clang does, it will eventually be the standard. -- Paulo
Apr 07 2014
prev sibling parent "Dejan Lekic" <dejan.lekic gmail.com> writes:
On Saturday, 5 April 2014 at 20:47:29 UTC, Walter Bright wrote:
 On 4/2/2014 3:07 PM, Walter Bright wrote:
 One downside of this proposal is that if we ever (perish the 
 thought!) attempted
 to interface to C++ templates, this design would preclude that.

Yes, this seems to be a fatal flaw. Another design that has evolved from these discussions and my discussions with Andrei on it: extern (C++, namespace = A.B) { void foo(); void bar(); } extern (C++, namespace = C) void foo(); bar(); // works A.B.bar(); // works foo(); // error: ambiguous C.foo(); // works alias C.foo foo; foo(); // works, calling C.foo() I really think the namespace semantics should be attached to the extern(C++) rather than be a separate pragma. Having the namespace= thing means that namespace isn't a keyword, and provides a general mechanism where we can add language specific information as necessary.

I actually like this idea the most. It is clean, and easy to understand.
Apr 07 2014
prev sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
 I think it's very low hanging fruit to add support for basic 
 C++ namespaces. Support for basically just set the mangled name 
 in a somewhat nice way, a pragma for example.

I think it is more important to think in term of strategic positions than whether it takes 1 or 2 weeks to implement a feature. Assumption: It is desirable to make the eco system more attractive for commercial projects. Key requirements: - Long term stability of the dev environment. - Access to mature libraries with significant backing (basically C/C++ libraries). - Easy integration with existing technology and systems (basically C/C++). - No lock-in (basically C/C++ interop). - Predictable dev environment that enables precise cost estimates. - Lowering costs/faster development than the alternatives (more convinient than C/C++) If you cannot assume that you can utilize a C++ library from D or if you have to assume that using a C++ library might incur a significant interfacing overhead (in terms of programmer's time) then D looks like a more risky proposition. The key difference between a commercial project and a hobby project is that the hobby project can fully adapt the requirements to the dev environment. A hobbyist game project can settle for a less capable physics engine or create a custom one, for fun. A commercial project will view that as costs that cut into profit margins and a potential source of failure in the market. That's a good reason to go with C++ instead of D. From a strategic point of view it is important to fully support those features you claim to support. If you can claim that interfacing with C++, except for templates, is easy, then you communicate that it is relatively easy to assess project costs. If you only claim that it is possible to interface with some of C++, but that it is kind of difficult under certain vaguely specified circumstances then I think you should wait until you have a better solution. What you absolutely don't want is to trick people into thinking that interfacing with C++ is easy, if it isn't, and have them discover that they are better off dumping D and doing it all over in C++.
Apr 06 2014