www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - extern(C++, NS)

reply Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
I'm having a lot of trouble with C++ namespaces.
The problem is, the namespace is not just attributed to the symbol in
D, but it's emulated as a named scope.

The trouble mostly appears in this situation:

file1.d
  extern(C++, NS) struct X;

file2.d
  extern(C++, NS) struct Y;

file3.d
  import file1, file2;
  X x; // nope
  Y y; // nope
  NS.X x; // NS has multiple definitions...
  NS.Y y; // NS has multiple definitions...


And various other configurations similar to this where multiple files
declare symbols in the same C++ namespace, and then something tries to
import more than one of them.
Circular imports of this sort always cause problems.

Additionally to that, I don't really want the C++ namespaces to be
visible to D; they should be for mangling purposes only.

So I try code like this:
  private extern(C++, NS) struct Thing {}
  alias Thing = NS.Thing;

The idea being that NS will not be available externally, and they
should use Thing in module scope instead, but that doesnt work with
errors:
  Error: module blah class blah.NS.Thing is private

It seems aliasing a private thing into the public namespace does not
make it accessible via that alias?

The only way I've managed to make any of those work is with proxy
modules, which static import the C++ module, and then `alias Thing =
NS.Thing` into the proxy module's scope. This is horrid, and it
doubles my module count. I haven't found another pattern that's
reliably workable.

Ideas?
Nov 28 2015
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/28/2015 8:40 PM, Manu via Digitalmars-d wrote:
 I'm having a lot of trouble with C++ namespaces.
 The problem is, the namespace is not just attributed to the symbol in
 D, but it's emulated as a named scope.
It is not "emulated" in D, it is an actual named scope in D.
 The trouble mostly appears in this situation:

 file1.d
    extern(C++, NS) struct X;

 file2.d
    extern(C++, NS) struct Y;

 file3.d
    import file1, file2;
    X x; // nope
    Y y; // nope
    NS.X x; // NS has multiple definitions...
    NS.Y y; // NS has multiple definitions...


 And various other configurations similar to this where multiple files
 declare symbols in the same C++ namespace, and then something tries to
 import more than one of them.
 Circular imports of this sort always cause problems.
D does not support C++ semantics. You cannot split namespaces into multiple files in D, nor can you add symbols to an existing namespace. For namespace NS, all the declarations in NS have to be in one file and between the { }, just like any other scope in D.
 Additionally to that, I don't really want the C++ namespaces to be
 visible to D; they should be for mangling purposes only.
We considered making them for mangling only, and rejected it as unworkable, because then two identical names in different namespaces could not be distinguished by the D symbol table system.
 So I try code like this:
    private extern(C++, NS) struct Thing {}
    alias Thing = NS.Thing;

 The idea being that NS will not be available externally, and they
 should use Thing in module scope instead, but that doesnt work with
 errors:
    Error: module blah class blah.NS.Thing is private

 It seems aliasing a private thing into the public namespace does not
 make it accessible via that alias?
Aliases do not change access permissions. They are just aliases.
 The only way I've managed to make any of those work is with proxy
 modules, which static import the C++ module, and then `alias Thing =
 NS.Thing` into the proxy module's scope. This is horrid, and it
 doubles my module count. I haven't found another pattern that's
 reliably workable.

 Ideas?
Stop trying to bash D into behaving like C++! It'll just make for horrid code (as you discovered) and make you miserable trying. D has an interface to C++; it does not have C++ semantics.
Nov 28 2015
next sibling parent reply Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 29 November 2015 at 14:57, Walter Bright via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 D does not support C++ semantics. You cannot split namespaces into multiple
 files in D, nor can you add symbols to an existing namespace. For namespace
 NS, all the declarations in NS have to be in one file and between the { },
 just like any other scope in D.
Then the feature fails. You can't put the entire STL in one file. C++ doesn't namespace per file, it generally namespaces per project... so this is the common case; every module define symbols in the same C++ namespace.
 Additionally to that, I don't really want the C++ namespaces to be
 visible to D; they should be for mangling purposes only.
We considered making them for mangling only, and rejected it as unworkable, because then two identical names in different namespaces could not be distinguished by the D symbol table system.
I understand, and that's fine, but it's not particularly useful unless I can make the namespace invisible and alias the namespaced symbols into D's module (user-accessible) scope. Otherwise importing 2 modules leads to conflicting namespace and symbol resolution is all messed up.
 So I try code like this:
    private extern(C++, NS) struct Thing {}
    alias Thing = NS.Thing;

 The idea being that NS will not be available externally, and they
 should use Thing in module scope instead, but that doesnt work with
 errors:
    Error: module blah class blah.NS.Thing is private

 It seems aliasing a private thing into the public namespace does not
 make it accessible via that alias?
Aliases do not change access permissions. They are just aliases.
Maybe a special case for C++ namespaces? Or some other solution that produces the same result. It's a weird sort of permission this one, it's not that the symbols are 'private'; I intend the user to use them, I just want the C++ hierarchy excluded from the symbol table and only accessibly by controlled/explicit alias.
 The only way I've managed to make any of those work is with proxy
 modules, which static import the C++ module, and then `alias Thing =
 NS.Thing` into the proxy module's scope. This is horrid, and it
 doubles my module count. I haven't found another pattern that's
 reliably workable.

 Ideas?
Stop trying to bash D into behaving like C++! It'll just make for horrid code (as you discovered) and make you miserable trying. D has an interface to C++; it does not have C++ semantics.
I don't think I'm doing that at all, I'm just trying to make some C++ code linkable to D, and it doesn't work at all. I think you misunderstood my entire post, I don't want C++ semantics at all, I just want to mangle like C++ for linkage, but the implementation doesn't let me do that. If anything, I'm trying to make C++ extern's behave like D semantics, but namespaces aren't a normal part of D, and don't really have idioms for dealing with this. C++ tends to namespace everything with the same namespace, and that means either I implement the entire C++ library in a single module (no way), or I face this mess. The feature just doesn't work beyond a single file linkage experiment, or I completely missed how I'm supposed to use it.
Nov 28 2015
parent Walter Bright <newshound2 digitalmars.com> writes:
On 11/28/2015 9:17 PM, Manu via Digitalmars-d wrote:
 On 29 November 2015 at 14:57, Walter Bright via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 D does not support C++ semantics. You cannot split namespaces into multiple
 files in D, nor can you add symbols to an existing namespace. For namespace
 NS, all the declarations in NS have to be in one file and between the { },
 just like any other scope in D.
Then the feature fails. You can't put the entire STL in one file. C++ doesn't namespace per file, it generally namespaces per project... so this is the common case; every module define symbols in the same C++ namespace.
You can also do this: extern (C++, NS) { mixin(import("file1.d")); mixin(import("file2.d")); }
 Maybe a special case for C++ namespaces?
Please, no. Unending confusion and bugs will result.
 C++ tends to namespace everything with the same namespace, and that
 means either I implement the entire C++ library in a single module
You only need the declarations, not the implementations.
Nov 29 2015
prev sibling next sibling parent Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
Upon further wasting-my-time, I am starting to suspect the forward
referencing issue may be a bigger problem than it appears.
I have lots of aliases, and most of them work, but some of them just
don't; "Error: identifier 'Kernel' of 'ep.Kernel' is not defined" (not
a very helpful message). It is though, it's defined right next to it's
companion, which is declared at the same time, in the same place, but
I don't get an error for that one. I think the problem here is that
the companion symbol isn't involved in a cross-module reference.

I try and reduce the problem, but it always disappears. It only
appears when the number of modules and interaction between them
becomes sufficient.
I suspect that whatever it is that causes namespace forward
referencing to fail may also be leading to this problem... just a
hunch, but it's the best I've got.
Nov 28 2015
prev sibling next sibling parent Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 29 November 2015 at 16:14, Manu <turkeyman gmail.com> wrote:
 Upon further wasting-my-time, I am starting to suspect the forward
 referencing issue may be a bigger problem than it appears.
 I have lots of aliases, and most of them work, but some of them just
 don't; "Error: identifier 'Kernel' of 'ep.Kernel' is not defined" (not
 a very helpful message). It is though, it's defined right next to it's
 companion, which is declared at the same time, in the same place, but
 I don't get an error for that one. I think the problem here is that
 the companion symbol isn't involved in a cross-module reference.

 I try and reduce the problem, but it always disappears. It only
 appears when the number of modules and interaction between them
 becomes sufficient.
 I suspect that whatever it is that causes namespace forward
 referencing to fail may also be leading to this problem... just a
 hunch, but it's the best I've got.
Progress... now when I compile, I get a pop-up dialog box that says: "object.Error (0): assert(0) or HLT instruction", and then writes "ICE: unsupported type const(char)[]" to the output.
Nov 29 2015
prev sibling next sibling parent reply Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 29 November 2015 at 19:42, Manu <turkeyman gmail.com> wrote:
 On 29 November 2015 at 16:14, Manu <turkeyman gmail.com> wrote:
 Upon further wasting-my-time, I am starting to suspect the forward
 referencing issue may be a bigger problem than it appears.
 I have lots of aliases, and most of them work, but some of them just
 don't; "Error: identifier 'Kernel' of 'ep.Kernel' is not defined" (not
 a very helpful message). It is though, it's defined right next to it's
 companion, which is declared at the same time, in the same place, but
 I don't get an error for that one. I think the problem here is that
 the companion symbol isn't involved in a cross-module reference.

 I try and reduce the problem, but it always disappears. It only
 appears when the number of modules and interaction between them
 becomes sufficient.
 I suspect that whatever it is that causes namespace forward
 referencing to fail may also be leading to this problem... just a
 hunch, but it's the best I've got.
Progress... now when I compile, I get a pop-up dialog box that says: "object.Error (0): assert(0) or HLT instruction", and then writes "ICE: unsupported type const(char)[]" to the output.
So, I think this compiler crash is when trying to C++ mangle types that it doesn't know how to deal with... interestingly, one of those types is typeof(null), which should work, and be mangled as nullptr_t ? Any slice type (ie, char[]) used anywhere within any scope attributed extern(C++) seems to cause DMD to crash. I have these extern(C++) structs and classes, and within them are a bunch of little D inline functions and helpers to make the C++ extern useful to D. This is where '[]' tends to appear, and the consequent compiler crashes. I have tried: extern (D) void helperMethod(char[] s) { ... }, but extern(D) doesn't seem to do anything here, and it still crashes. Options?
Nov 29 2015
parent Walter Bright <newshound2 digitalmars.com> writes:
On 11/29/2015 1:56 AM, Manu via Digitalmars-d wrote:
 Options?
I can't do anything with what you describe. Need reproducible test cases, not handwaving. It should also be in a separate thread rather than mixed up with the other issue.
Nov 29 2015
prev sibling next sibling parent Iain Buclaw via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 29 Nov 2015 6:17 am, "Manu via Digitalmars-d" <
digitalmars-d puremagic.com> wrote:
 On 29 November 2015 at 14:57, Walter Bright via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 D does not support C++ semantics. You cannot split namespaces into
multiple
 files in D, nor can you add symbols to an existing namespace. For
namespace
 NS, all the declarations in NS have to be in one file and between the {
},
 just like any other scope in D.
Then the feature fails. You can't put the entire STL in one file. C++ doesn't namespace per file, it generally namespaces per project... so this is the common case; every module define symbols in the same C++ namespace.
This (and response below about mangling) answers a recent question in a PR I made. I had noticed the same when writing a testsuite case, only to discover you can only declare `extern(C++, std)` once. For me, having all related code for a test close together is a nice-to-have though.
 Additionally to that, I don't really want the C++ namespaces to be
 visible to D; they should be for mangling purposes only.
We considered making them for mangling only, and rejected it as
unworkable,
 because then two identical names in different namespaces could not be
 distinguished by the D symbol table system.
I understand, and that's fine, but it's not particularly useful unless I can make the namespace invisible and alias the namespaced symbols into D's module (user-accessible) scope. Otherwise importing 2 modules leads to conflicting namespace and symbol resolution is all messed up.
Renamed imports should work here?
 So I try code like this:
    private extern(C++, NS) struct Thing {}
    alias Thing = NS.Thing;

 The idea being that NS will not be available externally, and they
 should use Thing in module scope instead, but that doesnt work with
 errors:
    Error: module blah class blah.NS.Thing is private

 It seems aliasing a private thing into the public namespace does not
 make it accessible via that alias?
Aliases do not change access permissions. They are just aliases.
Maybe a special case for C++ namespaces? Or some other solution that produces the same result. It's a weird sort of permission this one, it's not that the symbols are 'private'; I intend the user to use them, I just want the C++ hierarchy excluded from the symbol table and only accessibly by controlled/explicit alias.
You may have already noticed, but `extern(C++, NS)` behaves more like importing a module, but rather than the module being in a separate file, it's contents are put inplace of the braces. Like importing modules in D, the namespace name itself is not a strong encapsulation (unlike e.g D enums), so whether you use Thing or NS.Thing, both will resolve to the same symbol. The same should also be true when importing a namespace from another module. I think your idea with aliases was just wishful thinking, aliases themselves never worked like that.
Nov 29 2015
prev sibling next sibling parent reply Iain Buclaw via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 29 Nov 2015 10:42 am, "Manu via Digitalmars-d" <
digitalmars-d puremagic.com> wrote:
 On 29 November 2015 at 16:14, Manu <turkeyman gmail.com> wrote:
 Upon further wasting-my-time, I am starting to suspect the forward
 referencing issue may be a bigger problem than it appears.
 I have lots of aliases, and most of them work, but some of them just
 don't; "Error: identifier 'Kernel' of 'ep.Kernel' is not defined" (not
 a very helpful message). It is though, it's defined right next to it's
 companion, which is declared at the same time, in the same place, but
 I don't get an error for that one. I think the problem here is that
 the companion symbol isn't involved in a cross-module reference.

 I try and reduce the problem, but it always disappears. It only
 appears when the number of modules and interaction between them
 becomes sufficient.
 I suspect that whatever it is that causes namespace forward
 referencing to fail may also be leading to this problem... just a
 hunch, but it's the best I've got.
Progress... now when I compile, I get a pop-up dialog box that says: "object.Error (0): assert(0) or HLT instruction", and then writes "ICE: unsupported type const(char)[]" to the output.
I keep telling them to fix that. My suggestion of replacing them with meaningful errors was rejected.
Nov 29 2015
parent reply Jacob Carlborg <doob me.com> writes:
On 2015-11-29 11:19, Iain Buclaw via Digitalmars-d wrote:

 I keep telling them to fix that.  My suggestion of replacing them with
 meaningful errors was rejected.
"rejected", what!! Any assertion in the compiler is a bug. Or was that not from the compiler? -- /Jacob Carlborg
Nov 29 2015
next sibling parent reply Iain Buclaw via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 29 Nov 2015 11:30 am, "Jacob Carlborg via Digitalmars-d" <
digitalmars-d puremagic.com> wrote:
 On 2015-11-29 11:19, Iain Buclaw via Digitalmars-d wrote:

 I keep telling them to fix that.  My suggestion of replacing them with
 meaningful errors was rejected.
"rejected", what!! Any assertion in the compiler is a bug. Or was that
not from the compiler?

Someone put in those ICE's on the promise that at some point it would be
detected in semantic pass before the symbol mangling was requested.  That
promise was never kept.

For reference (or if you enjoy time travelling)
https://github.com/D-Programming-Language/dmd/pull/4661
Nov 29 2015
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/29/2015 2:40 AM, Iain Buclaw via Digitalmars-d wrote:
 On 29 Nov 2015 11:30 am, "Jacob Carlborg via Digitalmars-d"
 <digitalmars-d puremagic.com <mailto:digitalmars-d puremagic.com>> wrote:
  >
  > On 2015-11-29 11:19, Iain Buclaw via Digitalmars-d wrote:
  >
  >> I keep telling them to fix that.  My suggestion of replacing them with
  >> meaningful errors was rejected.
  >
  >
  > "rejected", what!! Any assertion in the compiler is a bug. Or was that not
 from the compiler?
  >

 Someone put in those ICE's on the promise that at some point it would be
 detected in semantic pass before the symbol mangling was requested.  That
 promise was never kept.

 For reference (or if you enjoy time travelling)
 https://github.com/D-Programming-Language/dmd/pull/4661
I commented there: "And any test cases that trigger these ICEs should be filed in bugzilla." What are the bugzilla issues?
Nov 29 2015
next sibling parent reply Iain Buclaw via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 29 November 2015 at 19:51, Walter Bright via Digitalmars-d <
digitalmars-d puremagic.com> wrote:

 On 11/29/2015 2:40 AM, Iain Buclaw via Digitalmars-d wrote:

 On 29 Nov 2015 11:30 am, "Jacob Carlborg via Digitalmars-d"
 <digitalmars-d puremagic.com <mailto:digitalmars-d puremagic.com>> wrote:
  >
  > On 2015-11-29 11:19, Iain Buclaw via Digitalmars-d wrote:
  >
  >> I keep telling them to fix that.  My suggestion of replacing them with
  >> meaningful errors was rejected.
  >
  >
  > "rejected", what!! Any assertion in the compiler is a bug. Or was that
 not
 from the compiler?
  >

 Someone put in those ICE's on the promise that at some point it would be
 detected in semantic pass before the symbol mangling was requested.  That
 promise was never kept.

 For reference (or if you enjoy time travelling)
 https://github.com/D-Programming-Language/dmd/pull/4661
I commented there: "And any test cases that trigger these ICEs should be filed in bugzilla." What are the bugzilla issues?
Many have been reported. https://issues.dlang.org/show_bug.cgi?id=14537 https://issues.dlang.org/show_bug.cgi?id=14178 https://issues.dlang.org/show_bug.cgi?id=14020 https://issues.dlang.org/show_bug.cgi?id=13870 https://issues.dlang.org/show_bug.cgi?id=13693
Nov 29 2015
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/29/2015 1:53 PM, Iain Buclaw via Digitalmars-d wrote:
 Many have been reported.

 https://issues.dlang.org/show_bug.cgi?id=14537
 https://issues.dlang.org/show_bug.cgi?id=14178
 https://issues.dlang.org/show_bug.cgi?id=14020
 https://issues.dlang.org/show_bug.cgi?id=13870
 https://issues.dlang.org/show_bug.cgi?id=13693
Thank you. Reporting bugs is the right solution, not papering over them. Some of those were misclassified, I fixed them.
Nov 29 2015
parent Iain Buclaw via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 29 November 2015 at 23:02, Walter Bright via Digitalmars-d <
digitalmars-d puremagic.com> wrote:

 On 11/29/2015 1:53 PM, Iain Buclaw via Digitalmars-d wrote:

 Many have been reported.

 https://issues.dlang.org/show_bug.cgi?id=14537
 https://issues.dlang.org/show_bug.cgi?id=14178
 https://issues.dlang.org/show_bug.cgi?id=14020
 https://issues.dlang.org/show_bug.cgi?id=13870
 https://issues.dlang.org/show_bug.cgi?id=13693
Thank you. Reporting bugs is the right solution, not papering over them.
Frankly, I thought things were going well and I was pushing it slowly in the right direction until someone did a rampage over it. Now I'm back to square one trying to work out what's going on with it, and it's going to need a lot more than papering to recover.
Nov 29 2015
prev sibling parent reply Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 30 Nov 2015 7:56 am, "Iain Buclaw via Digitalmars-d" <
digitalmars-d puremagic.com> wrote:
 On 29 November 2015 at 19:51, Walter Bright via Digitalmars-d <
digitalmars-d puremagic.com> wrote:
 On 11/29/2015 2:40 AM, Iain Buclaw via Digitalmars-d wrote:
 On 29 Nov 2015 11:30 am, "Jacob Carlborg via Digitalmars-d"
 <digitalmars-d puremagic.com <mailto:digitalmars-d puremagic.com>>
wrote:
  >
  > On 2015-11-29 11:19, Iain Buclaw via Digitalmars-d wrote:
  >
  >> I keep telling them to fix that.  My suggestion of replacing them
with
  >> meaningful errors was rejected.
  >
  >
  > "rejected", what!! Any assertion in the compiler is a bug. Or was
that not
 from the compiler?
  >

 Someone put in those ICE's on the promise that at some point it would be
 detected in semantic pass before the symbol mangling was requested.
That
 promise was never kept.

 For reference (or if you enjoy time travelling)
 https://github.com/D-Programming-Language/dmd/pull/4661
I commented there: "And any test cases that trigger these ICEs should be filed in bugzilla." What are the bugzilla issues?
Many have been reported. https://issues.dlang.org/show_bug.cgi?id=14537 https://issues.dlang.org/show_bug.cgi?id=14178 https://issues.dlang.org/show_bug.cgi?id=14020 https://issues.dlang.org/show_bug.cgi?id=13870 https://issues.dlang.org/show_bug.cgi?id=13693
I also logged 5 yesterday.
Nov 29 2015
parent Walter Bright <newshound2 digitalmars.com> writes:
On 11/29/2015 3:54 PM, Manu via Digitalmars-d wrote:
 I also logged 5 yesterday.
Thank you.
Nov 29 2015
prev sibling parent reply Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 29 November 2015 at 20:40, Iain Buclaw via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 29 Nov 2015 11:30 am, "Jacob Carlborg via Digitalmars-d"
 <digitalmars-d puremagic.com> wrote:
 On 2015-11-29 11:19, Iain Buclaw via Digitalmars-d wrote:

 I keep telling them to fix that.  My suggestion of replacing them with
 meaningful errors was rejected.
"rejected", what!! Any assertion in the compiler is a bug. Or was that not from the compiler?
Someone put in those ICE's on the promise that at some point it would be detected in semantic pass before the symbol mangling was requested. That promise was never kept. For reference (or if you enjoy time travelling) https://github.com/D-Programming-Language/dmd/pull/4661
Well they took a few hours of my life, and increased my anger level a couple of notches.
Nov 29 2015
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/29/2015 2:44 AM, Manu via Digitalmars-d wrote:
 Well they took a few hours of my life, and increased my anger level a
 couple of notches.
Per the pull request comments, file bugzilla issues any time such a message appears.
Nov 29 2015
parent Iain Buclaw via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 29 November 2015 at 19:52, Walter Bright via Digitalmars-d <
digitalmars-d puremagic.com> wrote:

 On 11/29/2015 2:44 AM, Manu via Digitalmars-d wrote:

 Well they took a few hours of my life, and increased my anger level a
 couple of notches.
Per the pull request comments, file bugzilla issues any time such a message appears.
I skip the middle-man and file github pull requests. It's much nicer to have an issue fixed than reported. It avoids lengthy mail threads down the line. :-)
Nov 29 2015
prev sibling next sibling parent Iain Buclaw via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 29 Nov 2015 10:57 am, "Manu via Digitalmars-d" <
digitalmars-d puremagic.com> wrote:
 On 29 November 2015 at 19:42, Manu <turkeyman gmail.com> wrote:
 On 29 November 2015 at 16:14, Manu <turkeyman gmail.com> wrote:
 Upon further wasting-my-time, I am starting to suspect the forward
 referencing issue may be a bigger problem than it appears.
 I have lots of aliases, and most of them work, but some of them just
 don't; "Error: identifier 'Kernel' of 'ep.Kernel' is not defined" (not
 a very helpful message). It is though, it's defined right next to it's
 companion, which is declared at the same time, in the same place, but
 I don't get an error for that one. I think the problem here is that
 the companion symbol isn't involved in a cross-module reference.

 I try and reduce the problem, but it always disappears. It only
 appears when the number of modules and interaction between them
 becomes sufficient.
 I suspect that whatever it is that causes namespace forward
 referencing to fail may also be leading to this problem... just a
 hunch, but it's the best I've got.
Progress... now when I compile, I get a pop-up dialog box that says: "object.Error (0): assert(0) or HLT instruction", and then writes "ICE: unsupported type const(char)[]" to the output.
So, I think this compiler crash is when trying to C++ mangle types that it doesn't know how to deal with... interestingly, one of those types is typeof(null), which should work, and be mangled as nullptr_t ? Any slice type (ie, char[]) used anywhere within any scope attributed extern(C++) seems to cause DMD to crash.
Correct, you will also get the same message with shared or immutable types, and static arrays. And I will hazard a guess at delegates and lazy parameters too. There is no technical limitation for this, you *can* pass these data structures to C/C++ (except shared and immutable) so long as the struct layout is matching on the other side. At the same time, it may be for the best if you pass the ptr and length explicitly.
Nov 29 2015
prev sibling next sibling parent reply Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 29 November 2015 at 20:17, Iain Buclaw via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 29 Nov 2015 6:17 am, "Manu via Digitalmars-d"
 <digitalmars-d puremagic.com> wrote:
 On 29 November 2015 at 14:57, Walter Bright via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 D does not support C++ semantics. You cannot split namespaces into
 multiple
 files in D, nor can you add symbols to an existing namespace. For
 namespace
 NS, all the declarations in NS have to be in one file and between the {
 },
 just like any other scope in D.
Then the feature fails. You can't put the entire STL in one file. C++ doesn't namespace per file, it generally namespaces per project... so this is the common case; every module define symbols in the same C++ namespace.
This (and response below about mangling) answers a recent question in a PR I made. I had noticed the same when writing a testsuite case, only to discover you can only declare `extern(C++, std)` once. For me, having all related code for a test close together is a nice-to-have though.
It's a serious problem. I haven't been able to find any reasonable solution. I've tried a bunch of stuff. I think the cleanest solutions would be to either fix this, or to allow public aliasing of private namespaces, that way the namespace is kept in it's box and never pollutes the user's module scope on import.
 Additionally to that, I don't really want the C++ namespaces to be
 visible to D; they should be for mangling purposes only.
We considered making them for mangling only, and rejected it as unworkable, because then two identical names in different namespaces could not be distinguished by the D symbol table system.
I understand, and that's fine, but it's not particularly useful unless I can make the namespace invisible and alias the namespaced symbols into D's module (user-accessible) scope. Otherwise importing 2 modules leads to conflicting namespace and symbol resolution is all messed up.
Renamed imports should work here?
How? I tried this every way I could think; import x.y.NS : Thing; // expects that NS is a file... import x.y : Thing = NS.Thing; // doesn't like 'NS.' in this statement import x.y : this = NS; // ...or something. yeah, I was getting hopeful I could only make this work with a proxy module, which doubles my module count: internal/thing.d: module x.y.internal.thing; extern(C++, NS) struct Thing {} thing.d: module x.y.thing; import x.y.internal.thing; // pollutes the local namespace with NS, but since it's not public it doesn't cascade outwards alias Thing = NS.Thing; // aliases to a public module-level symbol user.d: import x.y.thing; Thing t; // hooray, it works!
 So I try code like this:
    private extern(C++, NS) struct Thing {}
    alias Thing = NS.Thing;

 The idea being that NS will not be available externally, and they
 should use Thing in module scope instead, but that doesnt work with
 errors:
    Error: module blah class blah.NS.Thing is private

 It seems aliasing a private thing into the public namespace does not
 make it accessible via that alias?
Aliases do not change access permissions. They are just aliases.
Maybe a special case for C++ namespaces? Or some other solution that produces the same result. It's a weird sort of permission this one, it's not that the symbols are 'private'; I intend the user to use them, I just want the C++ hierarchy excluded from the symbol table and only accessibly by controlled/explicit alias.
You may have already noticed, but `extern(C++, NS)` behaves more like importing a module, but rather than the module being in a separate file, it's contents are put inplace of the braces.
Yup, but `import` doesn't seem to have tools to deal with this case.
 Like importing modules in D, the namespace name itself is not a strong
 encapsulation (unlike e.g D enums), so whether you use Thing or NS.Thing,
 both will resolve to the same symbol.  The same should also be true when
 importing a namespace from another module.
It all goes south when you realise that every file in a C++ project tends to be in the same namespace. Import 2 of them, and then they start hiding eachother, and it all goes south very quickly.
 I think your idea with aliases was just wishful thinking, aliases themselves
 never worked like that.
I thought aliases did produce a symbol in the scope they are declared? Or do you mean with the private thing? Yeah... Aliases are often used to sort out these sorts of scope/namespacing issues, I've seen it come up lots of times.
Nov 29 2015
next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On a related note, does D support inline namespaces? Apparently 
it affects mangling:

http://stackoverflow.com/questions/29764869/can-inline-namespaces-be-used-to-keep-backwards-compatibility-in-a-shared-librar

I use inline namespaces quite a bit and am curious of how D 
resolves those.
Nov 29 2015
next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Sunday, 29 November 2015 at 11:13:03 UTC, Ola Fosheim Grøstad 
wrote:
 On a related note, does D support inline namespaces? Apparently 
 it affects mangling:

 http://stackoverflow.com/questions/29764869/can-inline-namespaces-be-used-to-keep-backwards-compatibility-in-a-shared-librar

 I use inline namespaces quite a bit and am curious of how D 
 resolves those.
I wish someone would shed som light on this as inline namespaces is what libraries will use in the future in order to do versioning and target different architectures, the one marked "inline" is made active and can be directly accessed through "X::decl" or "X::version1::decl" in c++: namespace X { inline namespace version1 { decl.... } namespace version2 { decl.... } } Seems to me that D needs to embed clang and that the current bindings-only approach will not survive C++11 and later standards.
Nov 30 2015
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/30/2015 2:26 AM, Ola Fosheim Grøstad wrote:
 I wish someone would shed som light on this as inline namespaces is what
 libraries will use in the future in order to do versioning and  target
different
 architectures, the one marked "inline" is made active and can be directly
 accessed through "X::decl" or "X::version1::decl" in c++:

 namespace X {
       inline namespace version1 {
            decl....
       }
       namespace version2 {
            decl....
       }
 }

 Seems to me that D needs to embed clang and that the current bindings-only
 approach will not survive C++11 and later standards.
It'd be worthwhile to learn how D's name lookup system works before declaring it lame and insufficient: extern (C++, X) { extern (C++, version1) { enum e = 3; } } int x = e; int y = X.e; int z = X.version1.e; compiles successfully.
Nov 30 2015
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Monday, 30 November 2015 at 17:38:06 UTC, Walter Bright wrote:
 It'd be worthwhile to learn how D's name lookup system works 
 before declaring it lame and insufficient:
Nobody has said anything about lame. The issue is that you don't need to know of "version1" on the C++ side. One purpose is to use the "inline" as a switch, so that you can use macros to turn on and off different library subsets. "inline" is injected in front of namespaces that are to be accessible in the parent, and that injection can be done by a macro. But on the D side you need to know of "version1" if D does not parse C++ headers. Which is a maintenance burden.
Nov 30 2015
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/30/2015 10:51 AM, Ola Fosheim Grøstad wrote:
 On Monday, 30 November 2015 at 17:38:06 UTC, Walter Bright wrote:
 It'd be worthwhile to learn how D's name lookup system works before declaring
 it lame and insufficient:
Nobody has said anything about lame. The issue is that you don't need to know of "version1" on the C++ side.
Did you look at the example I posted?
 One purpose is to use the "inline" as a switch, so
 that you can use macros to turn on and off different library subsets. "inline"
 is injected in front of namespaces that are to be accessible in the parent, and
 that injection can be done by a macro.

 But on the D side you need to know of "version1" if D does not parse C++
 headers. Which is a maintenance burden.
Please examine the example I gave again before assuming how D works.
Nov 30 2015
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Monday, 30 November 2015 at 19:38:53 UTC, Walter Bright wrote:
 On 11/30/2015 10:51 AM, Ola Fosheim Grøstad wrote:
 On Monday, 30 November 2015 at 17:38:06 UTC, Walter Bright 
 wrote:
 It'd be worthwhile to learn how D's name lookup system works 
 before declaring
 it lame and insufficient:
Nobody has said anything about lame. The issue is that you don't need to know of "version1" on the C++ side.
Did you look at the example I posted?
Yes, the problem I see is: 1. You need to know about "version1" which is an internal namespace on the C++ side, so you cannot just create binding to the documented API, but need to go through the source code just to discover that "version1" exists. 2. If the library internals changes on the C++ side it causes problems for D application code, but not for C++ application code. 3. In order to keep the D and the C++ side call the same set of APIs (if desired) you also need to know on the D side whether the current C++ configuration has enabled "version1" or "version2" (+ a bunch of other potential variations). In essence the C++ model isn't friendly to foreign languages. They keep bolting on "neat hacks" to extend the language in nonbreaking "transparent" ways (on the C++ side).
Nov 30 2015
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/30/2015 12:47 PM, Ola Fosheim Grøstad wrote:
 [...]
Summary: if the C++ declarations change then the D ones that interface to it have to change, too. I'd have to say that's a given.
Nov 30 2015
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Monday, 30 November 2015 at 21:42:19 UTC, Walter Bright wrote:
 On 11/30/2015 12:47 PM, Ola Fosheim Grøstad wrote:
 [...]
Summary: if the C++ declarations change then the D ones that interface to it have to change, too. I'd have to say that's a given.
It might be a given, but as pure C++11 libraries become more common people will need a way to deal with inlined namespaces in a way that isn't annoying. And if the changes does not show up in the mangling, then it won't be caught at link-time either. We'll see...
Nov 30 2015
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 11/29/2015 12:13 PM, Ola Fosheim Grøstad wrote:
 On a related note, does D support inline namespaces? Apparently it
 affects mangling:

 http://stackoverflow.com/questions/29764869/can-inline-namespaces-be-used-to-keep-backwards-compatibility-in-a-shared-librar
Namespaces affect mangling. The inline keyword doesn't.
 I use inline namespaces quite a bit and am curious of how D resolves those.
string inlineNamespace(alias ns)(){ string s; foreach(m;__traits(allMembers,ns)) s~=`alias `~m~`=`~__traits(identifier,ns)~`.`~m~`;`; return s; } extern(C++,std){ extern(C++,version1){ void bar(){} } mixin(inlineNamespace!version1); extern(C++,version2){ void bar(){} } }
Nov 30 2015
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Monday, 30 November 2015 at 14:22:17 UTC, Timon Gehr wrote:
 On 11/29/2015 12:13 PM, Ola Fosheim Grøstad wrote:
 On a related note, does D support inline namespaces? 
 Apparently it
 affects mangling:

 http://stackoverflow.com/questions/29764869/can-inline-namespaces-be-used-to-keep-backwards-compatibility-in-a-shared-librar
Namespaces affect mangling. The inline keyword doesn't.
The problem is that the inlined namespace can change without affecting C++ code. That makes it difficult to make stable bindings for D as it is transparent in C++, but non-transparent in D. Right?
Nov 30 2015
prev sibling next sibling parent reply Daniel N <ufo orbiting.us> writes:
On Sunday, 29 November 2015 at 10:58:48 UTC, Manu wrote:
 On 29 November 2015 at 20:17, Iain Buclaw via Digitalmars-d
 I think your idea with aliases was just wishful thinking, 
 aliases themselves never worked like that.
I thought aliases did produce a symbol in the scope they are declared? Or do you mean with the private thing? Yeah... Aliases are often used to sort out these sorts of scope/namespacing issues, I've seen it come up lots of times.
I remember when this feature was under discussion, I tried to argue against extern c++ creating a new scope, but alas no avail. So my current workaround looks something like this(but I didn't use it on a large scale yet): private static struct Hidden { public: extern(C++, std) int fun(); } // autogenerate all aliases with 'static foreach'? alias fun = Hidden.std.fun; if only static foreach would get accepted one day...
Nov 29 2015
next sibling parent reply Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 29 November 2015 at 21:22, Daniel N via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Sunday, 29 November 2015 at 10:58:48 UTC, Manu wrote:
 On 29 November 2015 at 20:17, Iain Buclaw via Digitalmars-d
 I think your idea with aliases was just wishful thinking, aliases
 themselves never worked like that.
I thought aliases did produce a symbol in the scope they are declared? Or do you mean with the private thing? Yeah... Aliases are often used to sort out these sorts of scope/namespacing issues, I've seen it come up lots of times.
I remember when this feature was under discussion, I tried to argue against extern c++ creating a new scope, but alas no avail. So my current workaround looks something like this(but I didn't use it on a large scale yet): private static struct Hidden { public: extern(C++, std) int fun(); } // autogenerate all aliases with 'static foreach'? alias fun = Hidden.std.fun; if only static foreach would get accepted one day...
Wow... I just didn't quite get there >_< That's really horrible! But thanks! ;)
Nov 29 2015
parent Daniel N <ufo orbiting.us> writes:
On Sunday, 29 November 2015 at 11:29:58 UTC, Manu wrote:
 Wow... I just didn't quite get there >_<
 That's really horrible! But thanks! ;)
Sorry, my memory was failing me, I dug up the real source now, it was a while ago and I hacked around a lot before I got it working, this is what I ended up with. private extern(C++, std) { public: int fun(); } // autogenerate all aliases with 'static foreach'? alias fun = std.fun;
Nov 29 2015
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 11/29/2015 12:22 PM, Daniel N wrote:
 On Sunday, 29 November 2015 at 10:58:48 UTC, Manu wrote:
 On 29 November 2015 at 20:17, Iain Buclaw via Digitalmars-d
 I think your idea with aliases was just wishful thinking, aliases
 themselves never worked like that.
I thought aliases did produce a symbol in the scope they are declared? Or do you mean with the private thing? Yeah... Aliases are often used to sort out these sorts of scope/namespacing issues, I've seen it come up lots of times.
I remember when this feature was under discussion, I tried to argue against extern c++ creating a new scope, but alas no avail. So my current workaround looks something like this(but I didn't use it on a large scale yet): private static struct Hidden { public: extern(C++, std) int fun(); } // autogenerate all aliases with 'static foreach'? alias fun = Hidden.std.fun; if only static foreach would get accepted one day...
It is mostly about implementation now (and figuring out a couple of corner cases, for which the first version could just deny support). Something like this seems to be enough for your needs though: mixin({string s; foreach(m;__traits(allMembers,std)) s~=`alias `~m~`=std.`~m~`;`; return s; }());
Nov 29 2015
parent Daniel N <ufo orbiting.us> writes:
On Sunday, 29 November 2015 at 13:18:16 UTC, Timon Gehr wrote:
 It is mostly about implementation now (and figuring out a 
 couple of corner cases, for which the first version could just 
 deny support).
Awesome, much looking forwards to it!
 Something like this seems to be enough for your needs though:

 mixin({string s;
     foreach(m;__traits(allMembers,std))
         s~=`alias `~m~`=std.`~m~`;`;
     return s;
 }());
You're right, thanks! Works like a charm. :)
Nov 29 2015
prev sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, 29 November 2015 at 10:58:48 UTC, Manu wrote:
 On 29 November 2015 at 20:17, Iain Buclaw via Digitalmars-d 
 <digitalmars-d puremagic.com> wrote:
 I think your idea with aliases was just wishful thinking, 
 aliases themselves never worked like that.
I thought aliases did produce a symbol in the scope they are declared? Or do you mean with the private thing? Yeah... Aliases are often used to sort out these sorts of scope/namespacing issues, I've seen it come up lots of times.
Aliases usually seem to work a lot like copy-pasting. If you do something like alias New = Orig; then everywhere that New is used in the code, it's effectively replaced with Orig, and you never even see it in any error messages. It's pretty much just for the programmer's benefit - e.g. avoiding having to type out the entire import path for a symbol over and over: alias foo = some.pkg.somewhere.foo; But there's still really only one symbol that the compiler is dealing with. It's kind of like how the C/C++ compiler never really sees macros, though it's more controlled than that. For instance, try compiling this code on a 32-bit system: long val; size_t i = val; You'll get an error message complaining about trying to convert a long to a uint, just like if the code looked like long val; uint i = val; The only places that I can think of where aliases don't act quite like this are when they're not used to replace one symbol with another - e.g. with alias this or with using alias to bring a base class overload into the scope of a derived class. - Jonathan M Davis
Nov 29 2015
parent Walter Bright <newshound2 digitalmars.com> writes:
On 11/29/2015 4:36 AM, Jonathan M Davis wrote:
 But there's still really only one symbol that the compiler is dealing with.
It's
 kind of like how the C/C++ compiler never really sees macros, though it's more
 controlled than that.
More accurately, like C/C++ typedef behavior.
Nov 29 2015
prev sibling next sibling parent Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 29 November 2015 at 19:56, Manu <turkeyman gmail.com> wrote:
 ...
So I'm down to some link errors. I don't understand what's emitting these (or not, it seems)... I've messed around a lot. Is __ClassZ the typeinfo? Why would that be missing? Because it's extern(C++)? I tried removing that and it made no difference :/ 2> Error 42: Symbol Undefined _D15TypeInfo_Struct6__vtblZ 2>bin\Debug_x64\dplug.obj(dplug) 2> Error 42: Symbol Undefined _D14TypeInfo_Const6__vtblZ 2>bin\Debug_x64\dplug.obj(dplug) 2> Error 42: Symbol Undefined _D10TypeInfo_k6__initZ 2>bin\Debug_x64\dplug.obj(dplug) 2> Error 42: Symbol Undefined _D12TypeInfo_Aya6__initZ 2>bin\Debug_x64\dplug.obj(dplug) 2> Error 42: Symbol Undefined _D5libep9component9Component7__ClassZ
Nov 29 2015
prev sibling next sibling parent reply Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On Sunday, 29 November 2015 at 04:57:28 UTC, Walter Bright wrote:
 Aliases do not change access permissions. They are just aliases.
Note that this is a problem beyond Manu's use-case. Example: subtyping via alias this currently requires the alias'd entity to be public, contra the example given on TDPL p.231 (see https://issues.dlang.org/show_bug.cgi?id=10996 for details). This means that to use subtyping in practice requires internal implementation details to be revealed to the user, which isn't very nice :-(
Nov 29 2015
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, 29 November 2015 at 12:39:14 UTC, Joseph Rushton 
Wakeling wrote:
 On Sunday, 29 November 2015 at 04:57:28 UTC, Walter Bright 
 wrote:
 Aliases do not change access permissions. They are just 
 aliases.
Note that this is a problem beyond Manu's use-case. Example: subtyping via alias this currently requires the alias'd entity to be public, contra the example given on TDPL p.231 (see https://issues.dlang.org/show_bug.cgi?id=10996 for details). This means that to use subtyping in practice requires internal implementation details to be revealed to the user, which isn't very nice :-(
As long as aliases effectively disappear in the compiler once a replacement has been made, and they don't end up in error messages, allowing aliases to muck with anything about the original symbol seems like a recipe for disaster, though I can certainly see why folks would want it (and arguably, it would be a lot more user-friendly if the aliases showed up in the error messages along with the original symbol rather than outright disappearing). - Jonathan M Davis
Nov 29 2015
parent Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 29 November 2015 at 22:58, Jonathan M Davis via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Sunday, 29 November 2015 at 12:39:14 UTC, Joseph Rushton Wakeling wrote:
 On Sunday, 29 November 2015 at 04:57:28 UTC, Walter Bright wrote:
 Aliases do not change access permissions. They are just aliases.
Note that this is a problem beyond Manu's use-case. Example: subtyping via alias this currently requires the alias'd entity to be public, contra the example given on TDPL p.231 (see https://issues.dlang.org/show_bug.cgi?id=10996 for details). This means that to use subtyping in practice requires internal implementation details to be revealed to the user, which isn't very nice :-(
As long as aliases effectively disappear in the compiler once a replacement has been made, and they don't end up in error messages, allowing aliases to muck with anything about the original symbol seems like a recipe for disaster, though I can certainly see why folks would want it (and arguably, it would be a lot more user-friendly if the aliases showed up in the error messages along with the original symbol rather than outright disappearing). - Jonathan M Davis
This. This is my experience with aliases too. I have found disappearance of aliases has been a source of confusion on numerous occasions.
Nov 30 2015
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, 29 November 2015 at 04:57:28 UTC, Walter Bright wrote:
 D does not support C++ semantics. You cannot split namespaces 
 into multiple files in D, nor can you add symbols to an 
 existing namespace. For namespace NS, all the declarations in 
 NS have to be in one file and between the { }, just like any 
 other scope in D.
While I don't disagree with trying to limit how much of C++ gets dragged into D to support linking with C++ code, I don't see how this approach with namespaces is tenable in anything much more complicated than a toy example. C++ namespaces aren't used at all like D modules. Entire libraries are put into a single namespace. For instance, are you suggesting that we put all of the bindings for C++'s standard library in a single file? Large libraries such as Boost or Qt do often split up their namespaces into sub-namespaces, but they're still usually far larger than anyone would want to stick in a single file. It seems to me that the only way that the current behavior stands any chance of being tenable is if almost no one is using C++ bindings, and when they do, they keep them to an absolute bare minimum. It certainly doesn't fly well with binding something like the STL or Qt. - Jonathan M Davis
Nov 29 2015
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 11/29/2015 05:57 AM, Walter Bright wrote:
 D does not support C++ semantics. You cannot split namespaces into
 multiple files in D, nor can you add symbols to an existing namespace.
 For namespace NS, all the declarations in NS have to be in one file and
 between the { }, just like any other scope in D.
It's about namespace overloading. The following works, even though no scopes are actually extended with new symbols. module other; template foo(){ // a scope void foo(){} } // ---- import other; alias foo=other.foo; template foo(){ // another scope void foo(int){} } void main(){ foo(); // successful foo(2); // ditto }
Nov 29 2015
prev sibling parent reply Kagamin <spam here.lot> writes:
On Sunday, 29 November 2015 at 04:57:28 UTC, Walter Bright wrote:
 We considered making them for mangling only, and rejected it as 
 unworkable, because then two identical names in different 
 namespaces could not be distinguished by the D symbol table 
 system.
Didn't you show how two identical names can be distinguished with D symbol table system: On Sunday, 29 November 2015 at 18:29:14 UTC, Walter Bright wrote:
     file1.NS.X x;
     file2.NS.Y y;
It also works the same for C bindings: they share (empty) namespace, but identical C declarations can be distinguished in D if they are in different modules. Maybe it's better to ignore C namespaces and rely on D module system instead? Though I don't know why one would want to disallow access to a C++ namespace.
Nov 30 2015
parent reply Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 30 November 2015 at 20:12, Kagamin via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Sunday, 29 November 2015 at 04:57:28 UTC, Walter Bright wrote:
 We considered making them for mangling only, and rejected it as
 unworkable, because then two identical names in different namespaces could
 not be distinguished by the D symbol table system.
Didn't you show how two identical names can be distinguished with D symbol table system: On Sunday, 29 November 2015 at 18:29:14 UTC, Walter Bright wrote:
     file1.NS.X x;
     file2.NS.Y y;
It also works the same for C bindings: they share (empty) namespace, but identical C declarations can be distinguished in D if they are in different modules. Maybe it's better to ignore C namespaces and rely on D module system instead? Though I don't know why one would want to disallow access to a C++ namespace.
Exactly, the D module system would still be in place. Assuming they were in defferent modules, then the D module system would keep them out of conflict naturally, with rules identical to the normal D rules. I imagined this; C++ namespace is for mangling, D module is for scoping. That's not how it seems to be, so my intuition was dead wrong, but my weekend's experience has convinced me it would be better how I initially intuited. Thing is, we're presenting a C++ API to D, so we want to present it in D's terms, that is, the API is distributed among D modules in a way that makes sense to a D user. I don't want to present the API in C++ terms, and it's not even practical; stuffing the entire C++ API into a single D module is crazy. In the cases I'm interested in, the C++ API is possibly larger than the entire D codebase that's attached to it. Walter said this: "Stop trying to bash D into behaving like C++! [...]", which I was kind of offended by, because it couldn't have been further from my intent. I'm trying to bash C++ into behaving like D, and the best way to do that would be to say that C++ namespace is for mangling only, and expect that the dev will distribute the C++ symbols among D modules in such a way that makes sense to D developers consuming the API.
Nov 30 2015
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 11/30/2015 3:42 AM, Manu via Digitalmars-d wrote:
 That's not how it seems to be,
Are you still not understanding how name lookup works in D? (You won't be the first. I explain it to people over and over, and nobody gets it. I have no idea why it is so hard to understand.) C++ namespaces introduce scopes. The normal D lookup rules for scoped names applies. When names in C++ namespaces are mangled, they are mangled like C++ names would be, not like D names would be. Lookup rules, apply one by one until found: 1. Look up in current scope. 2. Look up in imported scopes. Error if more than one is found. 3. Go up a level, and goto 1.
Nov 30 2015
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 11/30/2015 3:42 AM, Manu via Digitalmars-d wrote:
 Exactly, the D module system would still be in place. Assuming they
 were in defferent modules, then the D module system would keep them
 out of conflict naturally, with rules identical to the normal D rules.
 I imagined this;
No need to imagine: "Namespaces create a new named scope that is imported into its enclosing scope." -- http://dlang.org/spec/attribute.html#namespace
 C++ namespace is for mangling, D module is for
 scoping. That's not how it seems to be, so my intuition was dead
 wrong, but my weekend's experience has convinced me it would be better
 how I initially intuited.
What about: file1.NS.X x; file2.NS.Y y; ?
Nov 30 2015
prev sibling parent Daniel Murphy <yebbliesnospam gmail.com> writes:
On 30/11/2015 10:42 PM, Manu via Digitalmars-d wrote:
 Exactly, the D module system would still be in place. Assuming they
 were in defferent modules, then the D module system would keep them
 out of conflict naturally, with rules identical to the normal D rules.
 I imagined this; C++ namespace is for mangling, D module is for
 scoping. That's not how it seems to be, so my intuition was dead
 wrong, but my weekend's experience has convinced me it would be better
 how I initially intuited. Thing is, we're presenting a C++ API to D,
 so we want to present it in D's terms, that is, the API is distributed
 among D modules in a way that makes sense to a D user. I don't want to
 present the API in C++ terms, and it's not even practical; stuffing
 the entire C++ API into a single D module is crazy. In the cases I'm
 interested in, the C++ API is possibly larger than the entire D
 codebase that's attached to it.
You're not the only one who thought it should be that way.
Nov 30 2015
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 11/29/2015 05:40 AM, Manu via Digitalmars-d wrote:
 The trouble mostly appears in this situation:

 file1.d
    extern(C++, NS) struct X;

 file2.d
    extern(C++, NS) struct Y;

 file3.d
    import file1, file2;
    X x; // nope
    Y y; // nope
Those two actually work for me.
    NS.X x; // NS has multiple definitions...
    NS.Y y; // NS has multiple definitions...
Nov 29 2015
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/28/2015 8:40 PM, Manu via Digitalmars-d wrote:
 The trouble mostly appears in this situation:

 file1.d
    extern(C++, NS) struct X;

 file2.d
    extern(C++, NS) struct Y;

 file3.d
    import file1, file2;
    X x; // nope
    Y y; // nope
    NS.X x; // NS has multiple definitions...
    NS.Y y; // NS has multiple definitions...
file1.NS.X x; file2.NS.Y y; works.
Nov 29 2015
parent reply deadalnix <deadalnix gmail.com> writes:
On Sunday, 29 November 2015 at 18:29:14 UTC, Walter Bright wrote:
 On 11/28/2015 8:40 PM, Manu via Digitalmars-d wrote:
 The trouble mostly appears in this situation:

 file1.d
    extern(C++, NS) struct X;

 file2.d
    extern(C++, NS) struct Y;

 file3.d
    import file1, file2;
    X x; // nope
    Y y; // nope
    NS.X x; // NS has multiple definitions...
    NS.Y y; // NS has multiple definitions...
file1.NS.X x; file2.NS.Y y; works.
Why not produce something similar to an overload set for C++ namespace ? An error needs to be issued only if X or Y is duplicated, otherwise, this is fine.
Nov 29 2015
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/29/2015 8:31 PM, deadalnix wrote:
 On Sunday, 29 November 2015 at 18:29:14 UTC, Walter Bright wrote:
 On 11/28/2015 8:40 PM, Manu via Digitalmars-d wrote:
 The trouble mostly appears in this situation:

 file1.d
    extern(C++, NS) struct X;

 file2.d
    extern(C++, NS) struct Y;

 file3.d
    import file1, file2;
    X x; // nope
    Y y; // nope
    NS.X x; // NS has multiple definitions...
    NS.Y y; // NS has multiple definitions...
file1.NS.X x; file2.NS.Y y; works.
Why not produce something similar to an overload set for C++ namespace ? An error needs to be issued only if X or Y is duplicated, otherwise, this is fine.
Because I'd rather have symbol table lookups done in a consistent manner, rather than special casing it everywhere. The above behavior is completely consistent with how everything else works, because it uses the exact same code.
Nov 29 2015
parent deadalnix <deadalnix gmail.com> writes:
On Monday, 30 November 2015 at 07:45:54 UTC, Walter Bright wrote:
 Why not produce something similar to an overload set for C++ 
 namespace ? An
 error needs to be issued only if X or Y is duplicated, 
 otherwise, this is fine.
Because I'd rather have symbol table lookups done in a consistent manner, rather than special casing it everywhere. The above behavior is completely consistent with how everything else works, because it uses the exact same code.
The proposed behavior is also not new (as per spec, alas it doesn't work in DMD), as it is the same as for multiple alias this.
Nov 30 2015