www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Is there any good reason why C++ namespaces are "closed" in D?

reply Atila Neves <atila.neves gmail.com> writes:
I understand that being able to "reopen" namespaces in C++ is 
contentious - anybody can add to the `std` namespace in their own 
code. D doesn't have anything like it, and instead has packages 
and modules. So far, so good.

But why does this not compile?

extern(C++, ns) { void foo(); }
extern(C++, ns) { void bar(); }

I could maybe understand the limitation if those functions had 
bodies since we'd be importing the namespace functionality from 
C++ in a sense (and even then I'm not sure it's a big enough 
deal). But all I'm trying to do here is tell the D compiler how 
to mangle symbols.

Why would this matter? Imagine a project that parses C++ headers 
and translates them to D declarations. Imagine that project is 
trying to parse `#include <vector>`. There will be many, many 
instances of `namespace std` in there, but such a 
not-so-hypothetical program can't just go through them and open 
and close `extern(C++, std)` as it goes along. Such a program can 
easily do that to `extern(C)`, but doing that to `extern(C++)` is 
for some reason not allowed.

(is there even any semantic difference? extern(C) for a 2nd time 
is just reopening the global namespace!)

One could simply manually `pragma(mangle)` everything up the 
wazoo, but unfortunately that doesn't work for templates, which, 
as it turns out, is pretty much everything inside the `std` 
namespace.

My only solution is to keep track of all namespaces at all times 
and then sort the declarations by namespace, which:

1) Is incredibly tedious
2) Might cause problems with the order of declarations, 
especially if macros are involved.

I can only assume nobody has tried calling a large C++ library 
from D (Qt doesn't count, no namespaces). Imagine manually 
organising namespaces in one huge bindings file instead of being 
able to copy the file layout of the C++ headers!

Sigh.

Atila
Jul 27 2018
next sibling parent kinke <noone nowhere.com> writes:
This limitation really seems to make no sense, especially since 
you can split up a C++ namespace across multiple D modules, just 
not inside a single module.
Jul 27 2018
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 27.07.2018 19:28, Atila Neves wrote:
 I understand that being able to "reopen" namespaces in C++ is 
 contentious - anybody can add to the `std` namespace in their own code. 
 D doesn't have anything like it, and instead has packages and modules. 
 So far, so good.
 
 But why does this not compile?
 
 extern(C++, ns) { void foo(); }
 extern(C++, ns) { void bar(); }
Both of the extern(C++, ns) declarations create a separate namespace declaration. (Which is needed to allow ns.foo and ns.bar respectively.) I.e. the reason is that it was easier to implement in the compiler. There might be a way to add support for it by overriding overloadInsert in Nspace.
Jul 27 2018
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/27/2018 10:28 AM, Atila Neves wrote:
 But all I'm trying to do here is tell the D 
 compiler how to mangle symbols.
Namespaces have semantic implications, too, such as overload resolutions. A namespace introduces a new scope, not just a mangling.
 But why does this not compile?
 extern(C++, ns) { void foo(); }
 extern(C++, ns) { void bar(); }
For the same reason that: struct ns { void foo(); } struct ns { void bar(); } doesn't. Being able to crack open a scope and stuff more symbols into it at any point in a program is just madness :-) However, one can do: ------ module A --------- extern(C++, ns) { void foo(); } ------ module B --------- extern(C++, ns) { void bar(); } ------ module C --------- import A,B; ns.foo(); // error, A.ns or B.ns? A.ns.foo(); // ok Because the compiler sees A.ns as utterly distinct from B.ns, although the mangling will be the same - any conflicts will be the linker's problem. This is how, for example, extern(C) declarations can exist in many files.
 Such a program can easily do that to `extern(C)`, but doing that to 
`extern(C++)` is for some reason not allowed. It is allowed. Just not reopening the same namespace. Namespaces are a botch in C++, and it is understandable that C++ code bases naturally have grown willy-nilly to utterly ignore any encapsulation principles. It's analogous to how monkey-patching in Ruby was seen initially as a cool feature, but eventually people learned the hard way what a disastrous idea it was.
Jul 27 2018
next sibling parent reply Laeeth Isharc <laeeth laeeth.com> writes:
On Friday, 27 July 2018 at 22:50:20 UTC, Walter Bright wrote:
 On 7/27/2018 10:28 AM, Atila Neves wrote:
 But all I'm trying to do here is tell the D compiler how to 
 mangle symbols.
Namespaces have semantic implications, too, such as overload resolutions. A namespace introduces a new scope, not just a mangling.
 But why does this not compile?
 extern(C++, ns) { void foo(); }
 extern(C++, ns) { void bar(); }
For the same reason that: struct ns { void foo(); } struct ns { void bar(); } doesn't. Being able to crack open a scope and stuff more symbols into it at any point in a program is just madness :-) However, one can do: ------ module A --------- extern(C++, ns) { void foo(); } ------ module B --------- extern(C++, ns) { void bar(); } ------ module C --------- import A,B; ns.foo(); // error, A.ns or B.ns? A.ns.foo(); // ok Because the compiler sees A.ns as utterly distinct from B.ns, although the mangling will be the same - any conflicts will be the linker's problem. This is how, for example, extern(C) declarations can exist in many files.
 Such a program can easily do that to `extern(C)`, but doing
that to `extern(C++)` is for some reason not allowed. It is allowed. Just not reopening the same namespace. Namespaces are a botch in C++, and it is understandable that C++ code bases naturally have grown willy-nilly to utterly ignore any encapsulation principles. It's analogous to how monkey-patching in Ruby was seen initially as a cool feature, but eventually people learned the hard way what a disastrous idea it was.
Thanks for the explanation, Walter. Can you think of a pragmatic solution to Atila's problem? Because it's getting in the way of a decent prize - to be able just to #include CPP headers and link with C++. Obviously some work elsewhere still to do, but translation of headers is worth quite a lot if you are a commercial user and don't have much time to write a first exploratory version. Already just having #include work for a lot of C libraries makes an immense difference. D "doesn't have libraries". Well there's some good stuff on code.dlang.org plus every C library - a few of those, so I hear. And with C++ on top it starts to become about as persuasive as "there are no good jobs in D". (Reminder - we are hiring and we pay well).
Jul 27 2018
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/27/2018 4:15 PM, Laeeth Isharc wrote:
 Can you think of a pragmatic solution to Atila's problem?
One way is for the C++ => D translator to gather all the members of a namespace before trying to emit them. Since D does not impose an order on declarations (unlike C++) it is not constrained to follow the same order.
Jul 27 2018
next sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Saturday, 28 July 2018 at 01:03:10 UTC, Walter Bright wrote:
 On 7/27/2018 4:15 PM, Laeeth Isharc wrote:
 Can you think of a pragmatic solution to Atila's problem?
One way is for the C++ => D translator to gather all the members of a namespace before trying to emit them. Since D does not impose an order on declarations (unlike C++) it is not constrained to follow the same order.
As mentioned in the original post, the gathering is going to be incredibly annoying and I suspect I'll run into problems with macros.
Jul 30 2018
parent Walter Bright <newshound2 digitalmars.com> writes:
On 7/30/2018 6:47 AM, Atila Neves wrote:
 As mentioned in the original post, the gathering is going to be incredibly 
 annoying
If you did it manually, sure. But altering the translator to do it?
 and I suspect I'll run into problems with macros.
I thought you were running the preprocessor first? Besides, I mentioned a solution in a reply to Manu.
Jul 30 2018
prev sibling parent reply Laeeth Isharc <Laeeth laeeth.com> writes:
On Saturday, 28 July 2018 at 01:03:10 UTC, Walter Bright wrote:
 On 7/27/2018 4:15 PM, Laeeth Isharc wrote:
 Can you think of a pragmatic solution to Atila's problem?
One way is for the C++ => D translator to gather all the members of a namespace before trying to emit them. Since D does not impose an order on declarations (unlike C++) it is not constrained to follow the same order.
So a new post preprocessor stage that parses the produced D code and regroups to group the declarations in the same namespace together ? Using DMD as a library or libdparse or something?
Jul 31 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/31/2018 3:34 PM, Laeeth Isharc wrote:
 On Saturday, 28 July 2018 at 01:03:10 UTC, Walter Bright wrote:
 On 7/27/2018 4:15 PM, Laeeth Isharc wrote:
 Can you think of a pragmatic solution to Atila's problem?
One way is for the C++ => D translator to gather all the members of a namespace before trying to emit them. Since D does not impose an order on declarations (unlike C++) it is not constrained to follow the same order.
So a new post preprocessor stage that parses the produced D code and regroups to group the declarations in the same namespace together ?  Using DMD as a library or libdparse or something?
I don't know how Atila's translator works. The htod one that I wrote would read and do the semantic processing on the entire file before walking the data structures and emitting the corresponding D code, so grouping the namespace declarations would be trivial. In fact, due to the nature of semantic processing, they would already be grouped together.
Aug 01 2018
parent Manu <turkeyman gmail.com> writes:
On Wed, 1 Aug 2018 at 02:10, Walter Bright via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 7/31/2018 3:34 PM, Laeeth Isharc wrote:
 On Saturday, 28 July 2018 at 01:03:10 UTC, Walter Bright wrote:
 On 7/27/2018 4:15 PM, Laeeth Isharc wrote:
 Can you think of a pragmatic solution to Atila's problem?
One way is for the C++ => D translator to gather all the members of a namespace before trying to emit them. Since D does not impose an order on declarations (unlike C++) it is not constrained to follow the same order.
So a new post preprocessor stage that parses the produced D code and regroups to group the declarations in the same namespace together ? Using DMD as a library or libdparse or something?
I don't know how Atila's translator works. The htod one that I wrote would read and do the semantic processing on the entire file before walking the data structures and emitting the corresponding D code, so grouping the namespace declarations would be trivial. In fact, due to the nature of semantic processing, they would already be grouped together.
None of this nuisance for Atila is necessary. You're just making busy-work for him at someone else's expense. Justify the design, and why it's worth the material cost to the users.
Aug 01 2018
prev sibling parent Ali <fakeemail example.com> writes:
On Friday, 27 July 2018 at 23:15:44 UTC, Laeeth Isharc wrote:

 Because it's getting in the way of a decent prize - to be able 
 just to #include CPP headers and link with C++.
Just wanted to +1000000 on this one Having this feature, and if marketed well, can be huge for D This is 10 times a bigger deal than any other thing working for D right now
Aug 03 2018
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
On Fri., 27 Jul. 2018, 3:55 pm Walter Bright via Digitalmars-d, <
digitalmars-d puremagic.com> wrote:

 Namespaces are a botch in C++, and it is understandable that C++ code
 bases
 naturally have grown willy-nilly to utterly ignore any encapsulation
 principles.
Correct. And D has modules. Solved. Literally nobody has ever wanted to use a C++ namespaces as a means of encapsulation in D. We *just* want to mangle our symbol name. We want to keep our code organised consistently with all other D code. Please, please, please... Please, please please please please please PLEASE support extern(C++, "string_ns") as a mangle-only variant. Current behaviour can coexist, but let us have a way to express a mangling request without changing the organisation of our D code. I suggest accepting string, since that will allow us to also access C++ namespaces that conflict with D keywords.
Jul 28 2018
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Friday, 27 July 2018 at 22:50:20 UTC, Walter Bright wrote:
 On 7/27/2018 10:28 AM, Atila Neves wrote:
 But all I'm trying to do here is tell the D compiler how to 
 mangle symbols.
Namespaces have semantic implications, too, such as overload resolutions. A namespace introduces a new scope, not just a mangling.
Should they, though?
 But why does this not compile?
 extern(C++, ns) { void foo(); }
 extern(C++, ns) { void bar(); }
For the same reason that: struct ns { void foo(); } struct ns { void bar(); }
Structs aren't namespaces, I wouldn't expect them to behave the same.
 doesn't. Being able to crack open a scope and stuff more 
 symbols into it at any point in a program is just madness :-)
Perhaps, but that's how C++ works.
 However, one can do:

 ------ module A ---------
     extern(C++, ns) { void foo(); }

 ------ module B ---------
     extern(C++, ns) { void bar(); }

 ------ module C ---------
     import A,B;
     ns.foo(); // error, A.ns or B.ns?
     A.ns.foo(); // ok

 Because the compiler sees A.ns as utterly distinct from B.ns, 
 although the mangling will be the same - any conflicts will be 
 the linker's problem.
I didn't know about this and it makes things better, but it's not a real solution to my problem.
 This is how, for example, extern(C) declarations can exist in 
 many files.

 Such a program can easily do that to `extern(C)`, but doing
that to `extern(C++)` is for some reason not allowed. It is allowed. Just not reopening the same namespace.
I'm arguing that reopening should be allowed.
Jul 30 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/30/2018 6:45 AM, Atila Neves wrote:
 On Friday, 27 July 2018 at 22:50:20 UTC, Walter Bright wrote:
 On 7/27/2018 10:28 AM, Atila Neves wrote:
 But all I'm trying to do here is tell the D compiler how to mangle symbols.
Namespaces have semantic implications, too, such as overload resolutions. A namespace introduces a new scope, not just a mangling.
Should they, though?
They do in C++. That was the whole point of adding namespaces: C: void ns_foo(); C++: namespace ns { void foo(); }
 Structs aren't namespaces, I wouldn't expect them to behave the same.
From a language perspective, they are namespaces.
 doesn't. Being able to crack open a scope and stuff more symbols into it at 
 any point in a program is just madness :-)
Perhaps, but that's how C++ works.
C++ has a lot of bizarre name lookup behavior.
 I didn't know about this and it makes things better, but it's not a real 
 solution to my problem.
See my other post doing this same thing with structs.
 I'm arguing that reopening should be allowed.
As detailed in another post, this opens a whole host of other problems. Even in C++, what names are visible in a namespace at any particular point in the compilation is a nebulous concept. (It is actually carefully specified, but you have to be a language lawyer / compiler implementer to know what they are - to the user it is erratic, random, and nebulous.) C++ gets away with this **** because programmers assume the fault lies within themselves. That doesn't work for D - they assume I'm an idiot. I get the bill. I posted a solution to Manu a couple times now, to you as a user it would look like: mixin(cppNamespace("ns", "void foo();")); and can be done with D today.
Jul 30 2018
parent reply Atila Neves <atila.neves gmail.com> writes:
On Monday, 30 July 2018 at 19:51:09 UTC, Walter Bright wrote:
 On 7/30/2018 6:45 AM, Atila Neves wrote:
 On Friday, 27 July 2018 at 22:50:20 UTC, Walter Bright wrote:
 On 7/27/2018 10:28 AM, Atila Neves wrote:
 But all I'm trying to do here is tell the D compiler how to 
 mangle symbols.
Namespaces have semantic implications, too, such as overload resolutions. A namespace introduces a new scope, not just a mangling.
Should they, though?
They do in C++. That was the whole point of adding namespaces: C: void ns_foo(); C++: namespace ns { void foo(); }
I meant "should they in D, though?". I don't want to import C++ semantics into D. I want D to correctly mangle C++ namespaced functions and change nothing at all about overload resolution in D.
 Structs aren't namespaces, I wouldn't expect them to behave 
 the same.
From a language perspective, they are namespaces.
Technically, yes. But not C++ namespaces.
 C++ has a lot of bizarre name lookup behavior.
It does. I don't think anyone is suggesting we copy it.
 I didn't know about this and it makes things better, but it's 
 not a real solution to my problem.
See my other post doing this same thing with structs.
It's not the same - if I want to link to std::vector and std::string, I'd expect them to be used in D as std.vector and std.string, not std.vector and HackyDThing0.std.string.
 I'm arguing that reopening should be allowed.
As detailed in another post, this opens a whole host of other problems. Even in C++, what names are visible in a namespace at any particular point in the compilation is a nebulous concept. (It is actually carefully specified, but you have to be a language lawyer / compiler implementer to know what they are - to the user it is erratic, random, and nebulous.)
Right, but D doesn't have to do any of that - as far as D is concerned it's just mangling. Well, as far as the typical D user that writes `extern(C++)` anyway.
Jul 31 2018
parent Walter Bright <newshound2 digitalmars.com> writes:
On 7/31/2018 1:43 AM, Atila Neves wrote:
 It's not the same - if I want to link to std::vector and std::string, I'd
expect 
 them to be used in D as std.vector and std.string, not std.vector and 
 HackyDThing0.std.string.
Calling them std.string will already cause problems, because there's an std.string in Phobos. You could call it core.stdcpp.string, analogously to core.stdc.string for string.h. Keep in mind that with 'alias' names can behave as if they are moved to another scope.
Aug 01 2018
prev sibling parent reply Manu <turkeyman gmail.com> writes:
On Fri., 27 Jul. 2018, 10:30 am Atila Neves via Digitalmars-d, <
digitalmars-d puremagic.com> wrote:

 I understand that being able to "reopen" namespaces in C++ is
 contentious - anybody can add to the `std` namespace in their own
 code. D doesn't have anything like it, and instead has packages
 and modules. So far, so good.

 But why does this not compile?

 extern(C++, ns) { void foo(); }
 extern(C++, ns) { void bar(); }

 I could maybe understand the limitation if those functions had
 bodies since we'd be importing the namespace functionality from
 C++ in a sense (and even then I'm not sure it's a big enough
 deal). But all I'm trying to do here is tell the D compiler how
 to mangle symbols.

 Why would this matter? Imagine a project that parses C++ headers
 and translates them to D declarations. Imagine that project is
 trying to parse `#include <vector>`. There will be many, many
 instances of `namespace std` in there, but such a
 not-so-hypothetical program can't just go through them and open
 and close `extern(C++, std)` as it goes along. Such a program can
 easily do that to `extern(C)`, but doing that to `extern(C++)` is
 for some reason not allowed.

 (is there even any semantic difference? extern(C) for a 2nd time
 is just reopening the global namespace!)

 One could simply manually `pragma(mangle)` everything up the
 wazoo, but unfortunately that doesn't work for templates, which,
 as it turns out, is pretty much everything inside the `std`
 namespace.

 My only solution is to keep track of all namespaces at all times
 and then sort the declarations by namespace, which:

 1) Is incredibly tedious
 2) Might cause problems with the order of declarations,
 especially if macros are involved.

 I can only assume nobody has tried calling a large C++ library
 from D (Qt doesn't count, no namespaces). Imagine manually
 organising namespaces in one huge bindings file instead of being
 able to copy the file layout of the C++ headers!

 Sigh.

 Atila
+1 You know how many times I've been upset about this, including the same day that the C++ namespace feature was merged without consulting anyone in the community that intended to use it. Make a PR that implements namespace as a string... I will use that fork of D forever.

Jul 28 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/28/2018 11:18 AM, Manu wrote:
 Make a PR that implements namespace as a string... I will use that fork of D 
 forever.
1. Look how it is mangled on the C++ side. (Use "grep" on the object file.) 2. Use: pragma(mangle, "the mangled name")
Jul 28 2018
next sibling parent reply Manu <turkeyman gmail.com> writes:
On Sat., 28 Jul. 2018, 8:25 pm Walter Bright via Digitalmars-d, <
digitalmars-d puremagic.com> wrote:

 On 7/28/2018 11:18 AM, Manu wrote:
 Make a PR that implements namespace as a string... I will use that fork
of D
 forever.
1. Look how it is mangled on the C++ side. (Use "grep" on the object file.) 2. Use: pragma(mangle, "the mangled name")
Don't troll me on this one, this is a very sensitive topic! I could have a legit mental breakdown ;)

Jul 28 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/28/2018 9:23 PM, Manu wrote:
 Don't troll me on this one, this is a very sensitive topic!
 I could have a legit mental breakdown ;)
Here's another method: ------ extern (C++, ns) { int foo() { return 1; } } mixin template X() { extern (C++, ns) { int bar() { return 2; } } } mixin X!() x; ------- and another: ----- extern (C++, ns) { int foo() { return 1; } } struct S { extern (C++, ns) { int bar() { return 2; } } } ----
Jul 29 2018
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
The name can be "transferred" into the global namespace using an alias.

This boilerplate can all be put inside of a string mixin.
Jul 29 2018
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Sunday, 29 July 2018 at 07:45:35 UTC, Walter Bright wrote:
 On 7/28/2018 9:23 PM, Manu wrote:
 Don't troll me on this one, this is a very sensitive topic!
 I could have a legit mental breakdown ;)
Here's another method: ------ extern (C++, ns) { int foo() { return 1; } } mixin template X() { extern (C++, ns) { int bar() { return 2; } } } mixin X!() x; -------
void main() { pragma(msg, __traits(allMembers, ns)); foo; bar; } $ dmd foo.d tuple("foo") foo.d(15): Error: undefined identifier bar That method doesn't compile.
 and another:

 -----
 extern (C++, ns) { int foo(); }

 struct S
 {
   extern (C++, ns) { int bar(); }
 }
 ----
void main() { foo; bar; } I changed them to be only declarations, since the goal is to call existing C++ code, not to define it in a D file. `foo` works as expected, but `bar`... foo.o:foo.d:function _Dmain: error: undefined reference to 'S::ns::bar()' collect2: error: ld returned 1 exit status Neither method works.
Jul 30 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/30/2018 7:20 AM, Atila Neves wrote:
 ------
 extern (C++, ns) { int foo() { return 1; } }

 mixin template X()
 {
   extern (C++, ns) { int bar() { return 2; } }
 }

 mixin X!() x;

 -------
void main() {     pragma(msg, __traits(allMembers, ns));     foo;     bar; } $ dmd foo.d tuple("foo") foo.d(15): Error: undefined identifier bar That method doesn't compile.
You'll need to add: alias bar = x.bar; which will add bar to the current scope.
 foo.o:foo.d:function _Dmain: error: undefined reference to 'S::ns::bar()'
Hmm, when I tested it the 'S::' prefix wasn't there. But when I retested it, it was. (!) I'll look into this.
Jul 30 2018
parent Walter Bright <newshound2 digitalmars.com> writes:
On 7/30/2018 1:05 PM, Walter Bright wrote:
 I'll look into this.
Check this: --- extern (C++, ns) { int foo(); } mixin template X() { extern (C++, ns) int bar(); } mixin X!() x; alias bar = x.ns.bar; void main() { foo(); bar(); pragma(msg, foo.mangleof); pragma(msg, bar.mangleof); } --- dmd -c test ?foo ns YAHXZ ?bar ns YAHXZ
Jul 30 2018
prev sibling next sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Sunday, 29 July 2018 at 03:20:29 UTC, Walter Bright wrote:
 On 7/28/2018 11:18 AM, Manu wrote:
 Make a PR that implements namespace as a string... I will use 
 that fork of D forever.
1. Look how it is mangled on the C++ side. (Use "grep" on the object file.) 2. Use: pragma(mangle, "the mangled name")
That a) doesn't scale in a real dynamic codebase (think templates), and b) is platform dependent and so isn't a proper solution. Honestly the only problem with Manu's suggestion is you can't expose `a::foo` and `b::foo` with the same signature within the same module due to (D) name collisions, although I don't see any reason why we can't do both. Then again I don't see any (non philosophical/compiler front end internal) issue why you can't reopen a namespace. D is supposed to be pragmatic, after all.
Jul 28 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/28/2018 11:06 PM, Nicholas Wilson wrote:
 Then again I don't see any (non philosophical/compiler front end internal)
issue 
 why you can't reopen a namespace. D is supposed to be pragmatic, after all.
Consider if a template reopens a namespace and throws a few more overloads in it. Then, what's in the namespace is dependent on which expansions are done, in which order. Throw in the inevitable circular references. Do people write code like that? Sure as shootin', they do, and they demand that it work, and file lots of bug reports about the erratic behavior. Next, consider a function body throwing a few more overloads in. Now, if the function body is compiled or not (and the compiler tries to avoid compiling bodies unless it has to) affects code that is outside of the function. C++ is full of stuff like that. The difference is, when code fails in some bizarre way, programmers blame themselves and throw money at Scott Meyers to educate them on how to avoid writing such code. For D, they blame me. The last time we fixed scope lookup to make it more complicated was with imports, and that took YEARS to sort out. So I'm a little reluctant to add features that will result in a rat's nest of problems I can neither explain nor fix, then someone will add 4000 incomprehensible lines to fix 2 cases and add 5 or 6 bizarre regressions in the process and people complain the compiler is unstable. :-)
Jul 29 2018
next sibling parent reply Manu <turkeyman gmail.com> writes:
On Sun., 29 Jul. 2018, 12:40 am Walter Bright via Digitalmars-d, <
digitalmars-d puremagic.com> wrote:

 On 7/28/2018 11:06 PM, Nicholas Wilson wrote:
 Then again I don't see any (non philosophical/compiler front end
internal) issue
 why you can't reopen a namespace. D is supposed to be pragmatic, after
all. Consider if a template reopens a namespace and throws a few more overloads in it. Then, what's in the namespace is dependent on which expansions are done, in which order. Throw in the inevitable circular references. Do people write code like that? Sure as shootin', they do, and they demand that it work, and file lots of bug reports about the erratic behavior. Next, consider a function body throwing a few more overloads in. Now, if the function body is compiled or not (and the compiler tries to avoid compiling bodies unless it has to) affects code that is outside of the function. C++ is full of stuff like that. The difference is, when code fails in some bizarre way, programmers blame themselves and throw money at Scott Meyers to educate them on how to avoid writing such code. For D, they blame me. The last time we fixed scope lookup to make it more complicated was with imports, and that took YEARS to sort out. So I'm a little reluctant to add features that will result in a rat's nest of problems I can neither explain nor fix, then someone will add 4000 incomprehensible lines to fix 2 cases and add 5 or 6 bizarre regressions in the process and people complain the compiler is unstable. :-)
I don't understand your claims that it would somehow become problematic or incomprehensible. Are you saying D's module system is incomprehensible? All we're asking for is that C++ namespaces do **nothing** except affect the mangling. We want the D module system to work verbatim, without any new behaviours or edge cases of any kind. All symbols are normal symbols in their normal D module namespaces, and resolved according to all the normal name lookup rules... just the symbol mangling will make it link properly, just like extern(C) and extern(C++). You're insisting we accept this complex solution you cooked up with new scopes introduced which are not module scopes, and introduce practical problems for most that try and use it, and then somehow tell us that we're asking to complicate the language when we beg for normal D behaviour as an option... It doesn't make sense. We don't want to 'open' or 'reopen' a namespace. We just want to tell the function how to mangle right. Show me "4000 incomprehensible lines" that were introduced by the existence of extern(C) or extern(C++)? Because asking for a namespace as nothing more than a mangling attribute will have no further effect than any other extern statement; that's the point!

Jul 29 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/29/2018 1:15 AM, Manu wrote:
 All we're asking for is that C++ namespaces do **nothing** except affect the 
 mangling.
If I do that, the next bug report will be: extern (C++, "ab") { void foo(); } extern (C++, "cd") { void foo(); } // Error, foo() is already declared foo(); // which one gets called? The reason namespaces were added to C++ is to not have such name collisions. Namespaces in C++ introduce a scope. D cannot interoperate with this without introducing a scope as well.
Jul 29 2018
next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Sunday, July 29, 2018 2:28:08 AM MDT Walter Bright via Digitalmars-d 
wrote:
 On 7/29/2018 1:15 AM, Manu wrote:
 All we're asking for is that C++ namespaces do **nothing** except affect
 the mangling.
If I do that, the next bug report will be: extern (C++, "ab") { void foo(); } extern (C++, "cd") { void foo(); } // Error, foo() is already declared foo(); // which one gets called? The reason namespaces were added to C++ is to not have such name collisions. Namespaces in C++ introduce a scope. D cannot interoperate with this without introducing a scope as well.
I guess that the argument at that point is that you would have to put them in separate D modules, just like you would if they were extern(D) functions. If that were the only problem, then that doesn't sound like a big one - especially if the documentation made it very clear that extern(C++) declarations did not affect the lookup rules, thus forcing you to rely on D's module system to deal with it all. All the extern(C++, NS) stuff does at that point is to enable linking with C++ and forces all of the normal D rules, which at least _sounds_ like it would be straightforward. If anything, it seems like it would make things much simpler. However, I've done nothing with C++ namespaces in D thus far. So, I really can't comment on the problems beyond what I've read in threads like this one. - Jonathan M Davis
Jul 29 2018
parent reply kinke <noone nowhere.com> writes:
On Sunday, 29 July 2018 at 11:03:43 UTC, Jonathan M Davis wrote:
 I guess that the argument at that point is that you would have 
 to put them in separate D modules, just like you would if they 
 were extern(D) functions.
Yep, that'd sound acceptable to me, implying that ``` extern(C++, cppns) { void foo(); } void foo(); ``` wouldn't work anymore, and particularly, this neither: ``` extern(C++, cppns) { extern(C++, nested) { void foo(); } void foo(); } ``` so that a straight C++ namespace => D module hierarchy mapping would probably be required in the general case: ``` // cppns/package.d module cppns; extern(C++, cppns) { void foo(); } // cppns/nested/package.d module cppns.nested; extern(C++, cppns) extern(C++, nested) { void foo(); } ```
Jul 29 2018
next sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Sunday, July 29, 2018 6:10:01 AM MDT kinke via Digitalmars-d wrote:
 On Sunday, 29 July 2018 at 11:03:43 UTC, Jonathan M Davis wrote:
 I guess that the argument at that point is that you would have
 to put them in separate D modules, just like you would if they
 were extern(D) functions.
Yep, that'd sound acceptable to me, implying that ``` extern(C++, cppns) { void foo(); } void foo(); ``` wouldn't work anymore, and particularly, this neither: ``` extern(C++, cppns) { extern(C++, nested) { void foo(); } void foo(); } ``` so that a straight C++ namespace => D module hierarchy mapping would probably be required in the general case: ``` // cppns/package.d module cppns; extern(C++, cppns) { void foo(); } // cppns/nested/package.d module cppns.nested; extern(C++, cppns) extern(C++, nested) { void foo(); } ```
Honestly, I'd expecting folks doing bindings for anything serious would be matching the layout of the C++ header files being translated. It becomes difficult to maintain bindings when their layout doesn't match the original files. Most of druntime's C bindings match the layout of the C headers that they're translating so that it's straightforward to find them (the primary exception being that OS-specific symbols from a standard header end up in a different file, which can be confusing and maybe shouldn't have been done, but those files follow the same layout - just in a different hierarchy under the OS's name). Anyone who didn't at least nominally make the layouts match would almost certainly run into maintenance problems in the long run. - Jonathan M Davis
Jul 29 2018
prev sibling parent reply Manu <turkeyman gmail.com> writes:
On Sun, 29 Jul 2018 at 05:10, kinke via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 [...]
 so that a straight C++ namespace => D module hierarchy mapping
 would probably be required in the general case:

 ```
 // cppns/package.d
 module cppns;
 extern(C++, "cppns") { void foo(); }

 // cppns/nested/package.d
 module cppns.nested;
 extern(C++, "cppns") extern(C++, "nested") { void foo(); }
 ```
It's beautiful! (but I added the quotes in there for you; without quotes is existing defined behaviour which introduces scopes)
Jul 29 2018
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/29/2018 1:52 PM, Manu wrote:
 On Sun, 29 Jul 2018 at 05:10, kinke via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 [...]
 so that a straight C++ namespace => D module hierarchy mapping
 would probably be required in the general case:

 ```
 // cppns/package.d
 module cppns;
 extern(C++, "cppns") { void foo(); }

 // cppns/nested/package.d
 module cppns.nested;
 extern(C++, "cppns") extern(C++, "nested") { void foo(); }
 ```
It's beautiful! (but I added the quotes in there for you; without quotes is existing defined behaviour which introduces scopes)
But that works now, I suggested it, and you didn't find it acceptable !!?!!
Jul 29 2018
parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Monday, 30 July 2018 at 02:09:37 UTC, Walter Bright wrote:
 On 7/29/2018 1:52 PM, Manu wrote:
 On Sun, 29 Jul 2018 at 05:10, kinke via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 [...]
 so that a straight C++ namespace => D module hierarchy mapping
 would probably be required in the general case:

 ```
 // cppns/package.d
 module cppns;
 extern(C++, "cppns") { void foo(); }

 // cppns/nested/package.d
 module cppns.nested;
 extern(C++, "cppns") extern(C++, "nested") { void foo(); }
 ```
It's beautiful! (but I added the quotes in there for you; without quotes is existing defined behaviour which introduces scopes)
But that works now, I suggested it, and you didn't find it acceptable !!?!!
No it doesn't. You missed
 (but I added the quotes in there for you; without quotes is 
 existing
 defined behaviour which introduces scopes)
With the above extern(C++, "cppns") (note the quotes) defines the mangling, the D module defines the scope. This is consistent with e.g. how the druntime bindings to C's standard library (with extern(C)) are used with extern(C) only affects the mangling, not introducing a scope, only that with extern(C++) you can have multiple things in different namespaces all called the same thing, so you actually need the scope as well as the mangling.
Jul 29 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/29/2018 7:50 PM, Nicholas Wilson wrote:
 No it doesn't.
I meant that you can today "reopen" namespace scopes by placing them in separate modules. You can (today) also "reopen" namespace scopes by placing them in separate mixin templates, or struct declarations. I posted examples.
Jul 29 2018
parent reply Manu <turkeyman gmail.com> writes:
On Sun, 29 Jul 2018 at 20:25, Walter Bright via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 7/29/2018 7:50 PM, Nicholas Wilson wrote:
 No it doesn't.
I meant that you can today "reopen" namespace scopes by placing them in separate modules.
That's not the same thing... you can create a _different one_ with the same name in a different module. If you import both modules, the namespaces conflict, so it's definitely not 'reopening' it as such. You need to make sure to not name the namespace when specifying symbols when you import 2 C++ modules, because it becomes ambiguous.
Jul 29 2018
parent Walter Bright <newshound2 digitalmars.com> writes:
On 7/29/2018 9:53 PM, Manu wrote:
 On Sun, 29 Jul 2018 at 20:25, Walter Bright via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 On 7/29/2018 7:50 PM, Nicholas Wilson wrote:
 No it doesn't.
I meant that you can today "reopen" namespace scopes by placing them in separate modules.
That's not the same thing... you can create a _different one_ with the same name in a different module.
That's right, I've said that before, and that's why I put "reopen" in quotes.
 If you import both modules, the namespaces conflict, so it's
 definitely not 'reopening' it as such.
No, they do not conflict. They are qualified by the module name, for exactly the same reason you can have the same name in different modules. And, as I posted before, 'alias' can be used to reference the name(s) as if they were in the current scope.
 You need to make sure to not name the namespace when specifying
 symbols when you import 2 C++ modules, because it becomes ambiguous.
Again, use qualification or an alias, just like is done with D names already.
Jul 30 2018
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 7/29/2018 1:52 PM, Manu wrote:
 On Sun, 29 Jul 2018 at 05:10, kinke via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 [...]
 so that a straight C++ namespace => D module hierarchy mapping
 would probably be required in the general case:

 ```
 // cppns/package.d
 module cppns;
 extern(C++, "cppns") { void foo(); }

 // cppns/nested/package.d
 module cppns.nested;
 extern(C++, "cppns") extern(C++, "nested") { void foo(); }
 ```
It's beautiful!
You must have missed my other post: ==================================================== Here's another method: ------ extern (C++, ns) { int foo() { return 1; } } mixin template X() { extern (C++, ns) { int bar() { return 2; } } } mixin X!() x; ------- and another: ----- extern (C++, ns) { int foo() { return 1; } } struct S { extern (C++, ns) { int bar() { return 2; } } } ----
Jul 29 2018
prev sibling next sibling parent ezneh <petitv.isat gmail.com> writes:
On Sunday, 29 July 2018 at 08:28:08 UTC, Walter Bright wrote:
 On 7/29/2018 1:15 AM, Manu wrote:
 All we're asking for is that C++ namespaces do **nothing** 
 except affect the mangling.
If I do that, the next bug report will be: extern (C++, "ab") { void foo(); } extern (C++, "cd") { void foo(); } // Error, foo() is already declared foo(); // which one gets called? The reason namespaces were added to C++ is to not have such name collisions. Namespaces in C++ introduce a scope. D cannot interoperate with this without introducing a scope as well.
Wouldn't something like this would prevent that : extern (C++, "ab") { void foo(); } extern (C++, "cd", "s") { void foo(); } // s is an optional D scope foo(); // works s.foo(); // works too Of course, it will imply some syntax change on the extern keyword, as a new optional parameter will be added.
Jul 29 2018
prev sibling next sibling parent reply Manu <turkeyman gmail.com> writes:
On Sun, 29 Jul 2018 at 01:30, Walter Bright via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 7/29/2018 1:15 AM, Manu wrote:
 All we're asking for is that C++ namespaces do **nothing** except affect the
 mangling.
If I do that, the next bug report will be: extern (C++, "ab") { void foo(); } extern (C++, "cd") { void foo(); } // Error, foo() is already declared foo(); // which one gets called? The reason namespaces were added to C++ is to not have such name collisions. Namespaces in C++ introduce a scope. D cannot interoperate with this without introducing a scope as well.
You're really reaching here. Of course, this error is legitimate and correct. Any D programmer knows they can't do this, and why would they expect they could? There's no way you'll get a bug report from someone complaining they can't multiply define symbols in the same scope. That's common sense. They will intuitively move the second declaration into a second module. ...or they'll use your existing mechanism; it's in there now, we can't remove it. But please support a variant where we can specify namespace as a string and opt-out of any funny business with scoping.
Jul 29 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/29/2018 1:45 PM, Manu wrote:
 There's no way you'll get a bug report from someone complaining they
 can't multiply define symbols in the same scope. That's common sense.
But then you cannot interface with this C++ code: namespace ab { void foo(); } namespace cd { void foo(); } Why would you find this acceptable?
Jul 29 2018
next sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Monday, 30 July 2018 at 02:15:57 UTC, Walter Bright wrote:
 On 7/29/2018 1:45 PM, Manu wrote:
 There's no way you'll get a bug report from someone 
 complaining they
 can't multiply define symbols in the same scope. That's common 
 sense.
But then you cannot interface with this C++ code: namespace ab { void foo(); } namespace cd { void foo(); } Why would you find this acceptable?
But you can if ab and cd are in different modules. The point is to decouple the mangling from the scope, leave the scope to D's module system, leave the mangling to extern(C++, "foo")
Jul 29 2018
parent Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Monday, 30 July 2018 at 02:53:43 UTC, Nicholas Wilson wrote:
 On Monday, 30 July 2018 at 02:15:57 UTC, Walter Bright wrote:
 On 7/29/2018 1:45 PM, Manu wrote:
 There's no way you'll get a bug report from someone 
 complaining they
 can't multiply define symbols in the same scope. That's 
 common sense.
But then you cannot interface with this C++ code: namespace ab { void foo(); } namespace cd { void foo(); } Why would you find this acceptable?
But you can if ab and cd are in different modules. The point is to decouple the mangling from the scope, leave the scope to D's module system, leave the mangling to extern(C++, "foo")
Not that this alleviates Alita's issues at all.
Jul 29 2018
prev sibling parent reply Manu <turkeyman gmail.com> writes:
On Sun., 29 Jul. 2018, 7:20 pm Walter Bright via Digitalmars-d, <
digitalmars-d puremagic.com> wrote:

 On 7/29/2018 1:45 PM, Manu wrote:
 There's no way you'll get a bug report from someone complaining they
 can't multiply define symbols in the same scope. That's common sense.
But then you cannot interface with this C++ code: namespace ab { void foo(); } namespace cd { void foo(); } Why would you find this acceptable?
ab.d ------ module ab; extern(C++, "ab") void foo(); cd.d ------ module cd; extern(C++, "cd") void foo(); Perfect! In 20 years, I've never seen 2 namespaces in the same file. And if the C++ code were like that, I'd break it into separate modules anyway, because that's what every D programmer would expect. Normal D module divisions map perfectly to every C++ program I've ever wanted to bind to yet. Conversely, single namespacs spread across many files appear all the time, and the current solution with disconnected namespaces scoped beneath the modules is extremely un-C++-like and problematic.
 You must have missed my other post:
 [...]
No, I feel like you've missed literally every post I've ever made on the topic. We ***do not want to use extern(C++) to scope and organise code***! That's what modules are for. D has modules, and they're good, and that's how we want to organise our code. I feel like I've conveyed that clearly. It doesn't need to be harder than that. We're perfectly happy with the way D works in every other case. We don't want 'cases' here. I can't understand your arguments saying the simpler design (ie, D modules) are complex, and cause for a torrent of bug reports. I haven't seen any bug reports about D modules making it impossible to organise code, and if that were true, then we have a serious problem with D's module design which carries WAAAY beyond extern(C++). I understand you're ideologically attached to this idea, and that's fine; I don't want to take anything away from you. We have what already exists, that can't go away now, but please just give us string namespaces as a mangle-only option. Not only will I shut up about it forever, but we will also be able to specify namespaces that conflict with D keywords, and also organise our modules just like all other D code ever.

Jul 29 2018
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/29/2018 8:05 PM, Manu wrote:
 ab.d
 ------
 module ab;
 extern(C++, "ab") void foo();
 
 
 cd.d
 ------
 module cd;
 extern(C++, "cd") void foo();
 
 Perfect!
extern(C++, ab) void foo(); extern(C++, cd) void foo(); Perfect! struct S1 { extern(C++, ns) void foo(); } alias foo = S1.ns.foo; struct S2 { extern(C++, ns) void bar(); } alias bar = S2.ns.bar; Perfect!
 We have what already exists, that can't go away now, but please just give us 
 string namespaces as a mangle-only option. Not only will I shut up about it 
 forever, but we will also be able to specify namespaces that conflict with D 
 keywords, and also organise our modules just like all other D code ever.
I'm the one that gets stuck with the fallout from bad designs. The solution I proposed above will work for you as best as I can tell. And it works right now, you don't have to wait for another version. --- You haven't explained why you can't just move the namespace ns declarations in one file together. C++ code is organized based on the wretched no-forward-references problem which doesn't exist in D.
Jul 30 2018
next sibling parent reply Daniel N <no public.email> writes:
On Monday, 30 July 2018 at 08:44:14 UTC, Walter Bright wrote:
   struct S1 { extern(C++, ns) void foo(); } alias foo = 
 S1.ns.foo;
   struct S2 { extern(C++, ns) void bar(); } alias bar = 
 S2.ns.bar;

 Perfect!
I tried that but it mangles wrong.. it includes "S1" which is not what you want, so I gave up binding to C++ and used C instead. pragma(msg, foo.mangleof); _ZN2S12ns3fooEv Even if it worked, you'd still see the full name in error messages and reflection. It's much harder to undo parts of one complex operation, compared to composing two simple building blocks. Couldn't we just add a new parameter to control scope or add a pragma or something?
Jul 30 2018
next sibling parent CommanderZot <no no.no> writes:
On Monday, 30 July 2018 at 12:07:31 UTC, Daniel N wrote:
 On Monday, 30 July 2018 at 08:44:14 UTC, Walter Bright wrote:
   struct S1 { extern(C++, ns) void foo(); } alias foo = 
 S1.ns.foo;
   struct S2 { extern(C++, ns) void bar(); } alias bar = 
 S2.ns.bar;

 Perfect!
I tried that but it mangles wrong.. it includes "S1" which is not what you want, so I gave up binding to C++ and used C instead. pragma(msg, foo.mangleof); _ZN2S12ns3fooEv Even if it worked, you'd still see the full name in error messages and reflection. It's much harder to undo parts of one complex operation, compared to composing two simple building blocks. Couldn't we just add a new parameter to control scope or add a pragma or something?
there also is an issue when using extern(C) in mixins. see https://issues.dlang.org/show_bug.cgi?id=12575
Jul 30 2018
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 7/30/2018 5:07 AM, Daniel N wrote:
 I tried that but it mangles wrong.. it includes "S1" which is not what you
want,
You're right, and I fixed that in a reply to Atila.
Jul 30 2018
prev sibling parent reply Manu <turkeyman gmail.com> writes:
On Mon, 30 Jul 2018 at 01:45, Walter Bright via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 7/29/2018 8:05 PM, Manu wrote:
 ab.d
 ------
 module ab;
 extern(C++, "ab") void foo();


 cd.d
 ------
 module cd;
 extern(C++, "cd") void foo();

 Perfect!
extern(C++, ab) void foo(); extern(C++, cd) void foo(); Perfect! struct S1 { extern(C++, ns) void foo(); } alias foo = S1.ns.foo; struct S2 { extern(C++, ns) void bar(); } alias bar = S2.ns.bar; Perfect!
 We have what already exists, that can't go away now, but please just give us
 string namespaces as a mangle-only option. Not only will I shut up about it
 forever, but we will also be able to specify namespaces that conflict with D
 keywords, and also organise our modules just like all other D code ever.
I'm the one that gets stuck with the fallout from bad designs. The solution I proposed above will work for you as best as I can tell. And it works right now, you don't have to wait for another version.
Sure it 'works', but it's an annoying point of friction, and it doesn't need to be that way. It requires over-specification of the namespace at calls, and it creates friction for scanning meta. It offers nothing, and only makes things harder and unintuitive. Why do you have such a strong opinion about a thing that you don't use? None of the customers ever suggested it should be like it is. Just let us mangle our symbols! We'll design our modules how we like; we're not morons, we want to present API's to users in logical and sensible ways.
 You haven't explained why you can't just move the namespace ns declarations in
 one file together.
Are you serious? https://github.com/dlang/druntime/pull/2259 <- There, I fixed it for you. I can't wait to get all the container classes in there too! If you really believe that, and not just trolling me, then click merge. Why would I want to have one gigantic module with everything dumped in it? No end-user wants that. We just want to use D as it is. What is so bad about D's module system that you plainly refuse to let us use it as it was intended? Just allow a string version. It's going to be okay. Everybody will be happier. The sky won't fall. When torrents of people complain, you can send every single one of them to me, tell me "I told you so", and I'll eat my hat.
Jul 30 2018
next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 7/30/18 12:45 PM, Manu wrote:
 On Mon, 30 Jul 2018 at 01:45, Walter Bright via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 On 7/29/2018 8:05 PM, Manu wrote:
 ab.d
 ------
 module ab;
 extern(C++, "ab") void foo();


 cd.d
 ------
 module cd;
 extern(C++, "cd") void foo();

 Perfect!
extern(C++, ab) void foo(); extern(C++, cd) void foo(); Perfect! struct S1 { extern(C++, ns) void foo(); } alias foo = S1.ns.foo; struct S2 { extern(C++, ns) void bar(); } alias bar = S2.ns.bar; Perfect!
What is this? I don't get what you are doing here.
 We have what already exists, that can't go away now, but please just give us
 string namespaces as a mangle-only option. Not only will I shut up about it
 forever, but we will also be able to specify namespaces that conflict with D
 keywords, and also organise our modules just like all other D code ever.
I'm the one that gets stuck with the fallout from bad designs. The solution I proposed above will work for you as best as I can tell. And it works right now, you don't have to wait for another version.
Sure it 'works', but it's an annoying point of friction, and it doesn't need to be that way. It requires over-specification of the namespace at calls, and it creates friction for scanning meta. It offers nothing, and only makes things harder and unintuitive. Why do you have such a strong opinion about a thing that you don't use? None of the customers ever suggested it should be like it is. Just let us mangle our symbols! We'll design our modules how we like; we're not morons, we want to present API's to users in logical and sensible ways.
 You haven't explained why you can't just move the namespace ns declarations in
 one file together.
Are you serious? https://github.com/dlang/druntime/pull/2259 <- There, I fixed it for you. I can't wait to get all the container classes in there too! If you really believe that, and not just trolling me, then click merge.
hehe, you need to put them all into one extern(C++, std), right? Not to mention having std as an identifier is somewhat problematic in D.
 Why would I want to have one gigantic module with everything dumped in
 it? No end-user wants that.
 We just want to use D as it is. What is so bad about D's module system
 that you plainly refuse to let us use it as it was intended?
 
 Just allow a string version. It's going to be okay. Everybody will be
 happier. The sky won't fall.
 When torrents of people complain, you can send every single one of
 them to me, tell me "I told you so", and I'll eat my hat.
 
While I agree with Manu that extern(C++, ns) would be better as just mangling, please don't just make the difference that it's a string literal vs. symbol. That difference is going to be confusing. Not to mention the abuse from calling CTFE functions. e.g.: string ns() { return "theNamespace"; } extern(C++, ns) or extern(C++, ns())? I'd suggest something like (shudder) extern(mangleC++, ns). None of this is attractive... Note that namespaces in D have been doable via templates or classes or structs for a long time. There is really no need to deal with C++ namespaces in D. -Steve
Jul 30 2018
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/30/2018 9:45 AM, Manu wrote:
 Sure it 'works', but it's an annoying point of friction, and it
 doesn't need to be that way.
You can reduce it to: mixin(cppNamespace("ns", "void foo();"));
 You haven't explained why you can't just move the namespace ns declarations in
 one file together.
Are you serious?
Yes, please explain why you can't coalesce the namespace declarations in one C++ file into one namespace declaration.
 When torrents of people complain, you can send every single one of
 them to me, tell me "I told you so", and I'll eat my hat.
Apologies don't pay the bills. C++ is full of such stuff, and the bill for it is staggering.
Jul 30 2018
next sibling parent reply Manu <turkeyman gmail.com> writes:
On Mon, 30 Jul 2018 at 13:25, Walter Bright via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 7/30/2018 9:45 AM, Manu wrote:
 Sure it 'works', but it's an annoying point of friction, and it
 doesn't need to be that way.
You can reduce it to: mixin(cppNamespace("ns", "void foo();"));
 You haven't explained why you can't just move the namespace ns declarations in
 one file together.
Are you serious?
Yes, please explain why you can't coalesce the namespace declarations in one C++ file into one namespace declaration.
We're talking about multiple C++ files, not one. Problems arise when you import 2 modules since the namespaces collide. You need to disambiguate with the D module identifier anyway, which self-defeats the whole design! The C++ namespaces are redundant. They just lead to user confusion, and more tedious metacrobatics when scanning for things. No scanning meta supports recursing into C++ namespaces.
 When torrents of people complain, you can send every single one of
 them to me, tell me "I told you so", and I'll eat my hat.
Apologies don't pay the bills. C++ is full of such stuff, and the bill for it is staggering.
I'm suggesting there will not be any such bug report. The result will be simpler and more intuitive, and there will be less complaints, not more. We don't want C++'s namespaces in D. I have no idea why you do... cus you go on and on about how complex and horrible they are. And now we have a thing that's not like C++ namespaces, and also not like normal D code (where normal D modules would be absolutely fine). I agree with you completely... I don't want C++ namespaces in D. I also don't want _anything like them_. We're all happy with the D module system, that's how we want to organise our code. Please let us organise our code using the D module system.
Jul 30 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/30/2018 2:12 PM, Manu wrote:
 We're all happy with the D
 module system, that's how we want to organise our code. Please let us
 organise our code using the D module system.
I have literally no idea what you mean. That's why I suggest you show what your C++ code looks like, and what you want to do with modules in D.
Jul 30 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
My issue is you're presenting solutions. But I have no idea what the problem
is, 
because every time I present a solution to the examples you give, you say it's 
no good, because your problem is something else.

I cannot reverse engineer what the issue is from your proposed solution.

My second point is that changing the language is a last resort solution, not a 
first resort.

Thirdly, C and C++ are loaded to the gills with 
seemed-like-a-good-idea-at-the-time solutions that turned out to have bad 
unintended consequences that bork up the language for everyone down the line. D 
has some of those, too.

Forgive me, but:

    extern (C++, "ns")

has a definite smell about it of something going awry, and the idea that it 
shouldn't introduce a scope because nobody relies on C++ namespaces being in a 
scope despite that being the whole point of namespaces is a giant red flag of 
something terribly wrong somewhere.
Jul 30 2018
next sibling parent reply Manu <turkeyman gmail.com> writes:
On Mon, 30 Jul 2018 at 23:15, Walter Bright via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 My issue is you're presenting solutions. But I have no idea what the problem
is,
 because every time I present a solution to the examples you give, you say it's
 no good, because your problem is something else.
I'm not asking for workarounds or 'solutions'. I know the workarounds very well, because I've been writing them repeatedly for years. I want to see this mistake corrected. It's not a case of "can't do the thing", this is a case of "i hate doing the thing (ie, workarounds), the results are particularly unsatisfying, and the whole basis for the problem is unfounded". We repeat it over and over. The case on trial today is that it can't be 'reopened', which is awkward in cases of generative programming (like Atila's case), and is a conversation that shouldn't even need to exist; a namespace given for mangling doesn't exhibit this issue. We can't specify some valid C++ namespace names that are D keywords. (also, 'std' is particularly annoying, since it conflicts with phobos) Other cases where it conflicts with itself when you import 2 modules with symbols spanning the same namespace, which is more common than not. The resolution is explicit disambiguation using the D module scope (which is the whole point of D modules), and so the C++ namespace scope is just redundant. Given your favourite example: ---- module a; extern(C++, ns) void foo(); ---- module b; extern(C++, ns) void foo(); ----- module c; import a, b; foo(); // error: ambiguous ns.foo(); // error, ambiguous (obviously) a.ns.foo(); // naturally, this works... it's the D module that correctly organises the symbol. 'ns' is worthless here Just like every other instance in D code ever where modules are used to organise symbols. I don't have to convince you that D modules work well... you need to convince us that D modules are insufficient. ns is just annoying complexity, and it interferes with other code. Atila's thing about 'reopening' namespaces is a non-issue if namespace was just for mangling. The whole class of problem ceases to exist. (I have been frustrated by this same problem too) Scanning meta doesn't have to learn to identify and recurse into C++ namespaces to traverse that edge case where a module has some C++ symbols. No scanning meta every written is equipped with that logic. There's no advantage to the ns scope, and it only brings challenges. None of any of our time ever needed to be wasted here. The feature as designed absolutely has not solved any form of problem. It has not saved more time than it's wasted, and it never will. Not to mention that it's ugly and leads to undesirable and unintuitive symbol names. When a C++ namespace spans modules (ie, the C++ namespace encloses the whole library's api), translation to D looks like this: module ns.submodule; extern(C++, ns) void foo(); The name is: ns.submodule.ns.foo(); // <- ns is already present at the head of the qualified name, there's no point repeating it. The converse case where modules are divided by their namespace (which naturally maps to D modules): module cpplib.ns; extern(C++, ns) void foo(); Now the name is: cpplib.ns.ns.foo(); // <- why would anyone want that? In both cases it's just a repeat of what's already in the module name. But the redundancy is more than a nuisance in certain forms of scanning meta. And got forbid the case where C++ namespaces are embedded (namespace for lib name, another for the module), and we have this: module lib_ns.module_ns; extrern(C++, lib_ns) extern(C++, module_ns) void foo(); The name is: lib_ns.module_ns.lib_ns.module_ns.foo(); // <- ....words can't even
 My second point is that changing the language is a last resort solution, not a
 first resort.
This isn't a last-resort, this was truly a first-resort... I started making this noise within some number of hours after the appearance of the design countable on my fingers. (far less aggressively, having not spent years of my life stewing on this) You've just blocked the conversation for sufficiently long that now you're able to say that sentence you just said. Was that a deliberate strategy? I feel like that strategy's been used before. That said, I'm not proposing a language 'change', we can just support a string version in parallel and everything's fine if we don't want to deprecate the scope version.
 Thirdly, C and C++ are loaded to the gills with
 seemed-like-a-good-idea-at-the-time solutions that turned out to have bad
 unintended consequences that bork up the language for everyone down the line. D
 has some of those, too.
extern(C++, ns) is the poster child of exactly that. In this case, it seemed-like-a-good-idea to one person and was implemented with no consultation of anyone. The design was never presented or scrutinised. It just merged, and when we promptly complained, our criticism were rejected on principle. Maybe we should write up a retro-DIP, and see if it passes review...?
 Forgive me, but:

     extern (C++, "ns")
It should be a string such that valid C++ namespace names that are grammatically invalid in the extern expression aren't arbitrarily rejected.
 has a definite smell about it of something going awry, and the idea that it
 shouldn't introduce a scope because nobody relies on C++ namespaces being in a
 scope despite that being the whole point of namespaces is a giant red flag of
 something terribly wrong somewhere.
C++ programmers depend on namespaces to scope stuff _in C++_. D programmers depend on modules to scope stuff (and it's a much better solution). Why don't you have faith in using modules to scope stuff? It's been working well for us all this time. People don't often complain that they have trouble scoping things intelligently in D. You need to argue a reason for the complexity, it's not my job to argue against the complexity that shouldn't ever have existed. Justifying the complexity is your burden of proof; it was never discussed or proven out. I can't argue my case any more than I have, but you haven't argued yours at all other than a feeling that is 'smells', and a sense of red flag that the D module system, which works perfectly fine in general, has some inexplicable weakness in this one case for some reason that's never been identified. You fear an unjustified torrent of bug reports if we were to fix this, but you don't acknowledge the constant stream of bug reports with the design as-is. You've got this backwards.
Jul 31 2018
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2018-07-31 10:12, Manu wrote:

 Given your favourite example:
 ----
 module a;
 extern(C++, ns) void foo();
 ----
 module b;
 extern(C++, ns) void foo();
 -----
 module c;
 import a, b;
 foo(); // error: ambiguous
 ns.foo(); // error, ambiguous (obviously)
 a.ns.foo(); // naturally, this works... it's the D module that
 correctly organises the symbol. 'ns' is worthless here
This works: a.foo(); You don't need "ns" in between the module name and the function. -- /Jacob Carlborg
Jul 31 2018
parent reply Manu <turkeyman gmail.com> writes:
On Tue., 31 Jul. 2018, 3:40 am Jacob Carlborg via Digitalmars-d, <
digitalmars-d puremagic.com> wrote:

 On 2018-07-31 10:12, Manu wrote:

 Given your favourite example:
 ----
 module a;
 extern(C++, ns) void foo();
 ----
 module b;
 extern(C++, ns) void foo();
 -----
 module c;
 import a, b;
 foo(); // error: ambiguous
 ns.foo(); // error, ambiguous (obviously)
 a.ns.foo(); // naturally, this works... it's the D module that
 correctly organises the symbol. 'ns' is worthless here
This works: a.foo(); You don't need "ns" in between the module name and the function.
Right... But did you miss the point? The D module does the organisation (as you show). The ns offers nothing and creates other kinds of problems. Just because name resolution traverses the namespace (in simple cases), there is an entire language of complexity that interacts with that name lookup, and as far as I know, it has never proven useful, but rather, only complicated and annoying leading to boilerplate and hacks in certain situations. (ie, this thread exists and many others)
Jul 31 2018
parent reply Rubn <where is.this> writes:
On Tuesday, 31 July 2018 at 16:23:55 UTC, Manu wrote:
 On Tue., 31 Jul. 2018, 3:40 am Jacob Carlborg via 
 Digitalmars-d, < digitalmars-d puremagic.com> wrote:

 On 2018-07-31 10:12, Manu wrote:

 Given your favourite example:
 ----
 module a;
 extern(C++, ns) void foo();
 ----
 module b;
 extern(C++, ns) void foo();
 -----
 module c;
 import a, b;
 foo(); // error: ambiguous
 ns.foo(); // error, ambiguous (obviously)
 a.ns.foo(); // naturally, this works... it's the D module 
 that
 correctly organises the symbol. 'ns' is worthless here
This works: a.foo(); You don't need "ns" in between the module name and the function.
Right... But did you miss the point? The D module does the organisation (as you show). The ns offers nothing and creates other kinds of problems. Just because name resolution traverses the namespace (in simple cases), there is an entire language of complexity that interacts with that name lookup, and as far as I know, it has never proven useful, but rather, only complicated and annoying leading to boilerplate and hacks in certain situations. (ie, this thread exists and many others)
Can you give some examples of those certain situations? It would help clear what is wrong with how it is currently implemented. One thing I don't like is that the C++ namespaces takes the name. So if you try to import a module that has C++ namespace of the same with the existing module, then you'll get an error. For effectively no reason, because as you say that namespace is useless and just occupies a name that could otherwise be used for the module name.
Jul 31 2018
parent Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Tuesday, 31 July 2018 at 23:02:16 UTC, Rubn wrote:
 One thing I don't like is that the C++ namespaces takes the 
 name. So if you try to import a module that has C++ namespace 
 of the same with the existing module, then you'll get an error. 
 For effectively no reason, because as you say that namespace is 
 useless and just occupies a name that could otherwise be used 
 for the module name.
Indeed, case in point: std
Jul 31 2018
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/31/2018 1:12 AM, Manu wrote:
 Given your favourite example:
 ----
 module a;
 extern(C++, ns) void foo();
 ----
 module b;
 extern(C++, ns) void foo();
 -----
 module c;
 import a, b;
 foo(); // error: ambiguous
 ns.foo(); // error, ambiguous (obviously)
 a.ns.foo(); // naturally, this works... it's the D module that
 correctly organises the symbol. 'ns' is worthless here
You can write it like this: ---- module a; extern(C++, ns) void foo(); alias foo = ns.foo; ---- module b; extern(C++, ns) void foo(); alias foo = ns.foo; ----- import a,b; a.foo(); // calls a.ns.foo() b.foo(); // calls b.ns.foo()
 When a C++ namespace spans modules (ie, the C++ namespace encloses the
 whole library's api), translation to D looks like this:
 
 module ns.submodule;
 extern(C++, ns) void foo();
 
 The name is:
 ns.submodule.ns.foo(); // <- ns is already present at the head of the
 qualified name, there's no point repeating it.
So don't repeat it. There is no particular reason to use that naming convention for an ns namespace. As I wrote to Atila, using 'std' as a package name isn't going to work very well anyway because it's already used as a root package in Phobos.
 The converse case where modules are divided by their namespace (which
 naturally maps to D modules):
 
 module cpplib.ns;
 extern(C++, ns) void foo();
 
 Now the name is:
 cpplib.ns.ns.foo(); // <- why would anyone want that?
Why indeed. Don't do that. I don't see any reason to. We've put things like string.h in core.stdc.string, and nobody has complained they cannot just type "import string;". It works fine. Allow me to refer to: https://github.com/dlang/druntime/blob/master/src/core/stdcpp/exception.d It's where std::exception goes -> core.stdcpp.exception In it, you'll find some extern(C++,std) declarations. The file can be imported as: import core.stdcpp.exception; or: import core.stdcpp.exception : std; or any of a number of other ways to import it and set up aliases (if one prefers) to use as shortcuts to the name.
 But the redundancy is more than a nuisance in certain forms of scanning meta.
As I mentioned, you can use alias to refer to names in other scopes.
 And got forbid the case where C++ namespaces are embedded (namespace
 for lib name, another for the module), and we have this:
 
 module lib_ns.module_ns;
 extrern(C++, lib_ns) extern(C++, module_ns) void foo();
 
 The name is:
 lib_ns.module_ns.lib_ns.module_ns.foo(); // <- ....words can't even
I have no idea why it would be necessary to write such. I suspect you are unfamiliar with the uses of 'alias' to refer from one scope to names in another.
 Was that a deliberate
 strategy? I feel like that strategy's been used before.
You repeatedly impugn my motives and/or my mental stability. While that doesn't bother me, it really does not help your case. Please just stick to the technical issue. Believe it or not, I really want to help you (and Laeeth and Atila) be successful with this.
Aug 01 2018
next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Wednesday, August 1, 2018 4:02:39 AM MDT Walter Bright via Digitalmars-d 
wrote:
 On 7/31/2018 1:12 AM, Manu wrote:
 Given your favourite example:
 ----
 module a;
 extern(C++, ns) void foo();
 ----
 module b;
 extern(C++, ns) void foo();
 -----
 module c;
 import a, b;
 foo(); // error: ambiguous
 ns.foo(); // error, ambiguous (obviously)
 a.ns.foo(); // naturally, this works... it's the D module that
 correctly organises the symbol. 'ns' is worthless here
You can write it like this: ---- module a; extern(C++, ns) void foo(); alias foo = ns.foo; ---- module b; extern(C++, ns) void foo(); alias foo = ns.foo; ----- import a,b; a.foo(); // calls a.ns.foo() b.foo(); // calls b.ns.foo()
Not to say that that can't work, but I have to say that it seems pretty ugly if using extern(C++, NS) requires a bunch of aliases just to use symbols normally. If the namespace were just part of the mangling, none of those aliases would be necessary. All in all, it just seems like having the namespaces add scoping just gets in the way - especially when they would normally get the necessary scoping from being put into separate D modules. Reading through this thread, and thinking about the issue, I don't see any advantage to the current behavior over having it just affect mangling other than the fact that that's how it currently works. All of the potential complaints that you talk about seem like they at least _should_ be a non-issue given that folks don't complain that way about D's module system for non-C++ functions - but it's certainly true that even engineers aren't always logical or reasonable. However, if we were discussing a DIP for implementing namespaces for C++, based on my current understanding of the matter, I'd definitely argue that extern(C++) with namespaces should just affect mangling, since that approach seems much more straightforward and much more in line with how other languages are handled, particularly since the scoping aspect is already going to be handled by D's module system anyway. As it stands, it just seems like the language is forcing that all C++ functions be put inside of structs to namespace them on top of them being put into a module. And that's downright awkward, even if it can work. Certainly, it does come across like you didn't trust the D module system to do its job for some reason. - Jonathan M Davis
Aug 01 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/1/2018 10:24 AM, Jonathan M Davis wrote:
 Not to say that that can't work, but I have to say that it seems pretty ugly
 if using extern(C++, NS) requires a bunch of aliases just to use symbols
 normally.
What is normal is a slippery concept, especially when one is comparing different lookup rules between languages. D modules do not a 1:1 correspondence with C++ namespaces, either (not even close). Aliases are a normal and highly useful D tool to copy names from one scope to another.
 Certainly, it does come across like
 you didn't trust the D module system to do its job for some reason.
Reorganizing the code into modules means potentially forcing users to split code from one C++ file into multiple D files. How's that really going to work if you have a translation tool? One of the aspects of Java I didn't care for was forcing each class into its own file. So while Manu is clearly happy with cutting up a C++ file into multiple D files, I doubt that is universal. His proposal would pretty much require that for anyone trying to work with C++ namespaces who ever has a name collision/hijack or wants to make the code robust against collision/hijacking. An example of silent hijacking: extern (C++, "ab") void foo(long); // original code ... lots of code ... extern (C++, "cd") void foo(int); // added later by intern, should have been // placed in another module ... a thousand lines later ... foo(0); // OOPS! now calling cd.foo() rather than ab.foo(), D sux You might say "nobody would ever write code like that." But that's like the C folks saying real C programmers won't write: int a[10]; for (int i = 0; i <= 10; ++i) ...a[i]... But we both know they do just often enough for it to be a disaster. Now, with D: extern (C++, ab) void foo(long); foo(0); // works! --- extern (C++, ab) void foo(long); extern (C++, ab) void foo(int); // error! --- extern (C++, ab) void foo(long); extern (C++, cd) void foo(int); foo(0); // error! I juxtaposed the lines so it's obvious. It's not so obvious when there's a thousand lines of code between each of those lines. It's even worse when foo(long) sends a birthday card to your daughter, and foo(int) launches nuclear missiles. Yes, this extra protection comes at a cost - you'll have to type a bit more. Just like D doesn't allow implicit declaration of variables, requires static typing, and variables are always initialized unless you explicitly use `= void`. The protection is worth it, and is part of D's philosophy. I hope that adequately answers the "for some reason" :-)
Aug 01 2018
next sibling parent reply Rubn <where is.this> writes:
On Wednesday, 1 August 2018 at 23:04:01 UTC, Walter Bright wrote:
 An example of silent hijacking:

    extern (C++, "ab") void foo(long); // original code
    ... lots of code ...
    extern (C++, "cd") void foo(int); // added later by intern, 
 should have been
                                      // placed in another module
    ... a thousand lines later ...
    foo(0); // OOPS! now calling cd.foo() rather than ab.foo(), 
 D sux

 You might say "nobody would ever write code like that." But 
 that's like the C folks saying real C programmers won't write:
You can do that today, just remove the "extern(C++, ...)" part and you have the same issue. Why should C++ with namespaces be safer than just regular D ? I don't understand, if it is such a huge gigantic problem why didn't you do anything to solve this problem in regards to D then ?
Aug 01 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/1/2018 7:09 PM, Rubn wrote:
 On Wednesday, 1 August 2018 at 23:04:01 UTC, Walter Bright wrote:
 An example of silent hijacking:

    extern (C++, "ab") void foo(long); // original code
    ... lots of code ...
    extern (C++, "cd") void foo(int); // added later by intern, should have
been
                                      //
placed in another module
    ... a thousand lines later ...
    foo(0); // OOPS! now calling cd.foo() rather than ab.foo(), D sux

 You might say "nobody would ever write code like that." But that's like the C 
 folks saying real C programmers won't write:
You can do that today, just remove the "extern(C++, ...)" part and you have the same issue. Why should C++ with namespaces be safer than just regular D ? I don't understand, if it is such a huge gigantic problem why didn't you do anything to solve this problem in regards to D then ?
The difference is those names are supposedly in different namespaces, given that the code is converted from C++: namespace ab { void foo(long); } ... lots of code ... namespace cd { void foo(int); } where the foo()'s do not conflict with each other, and a user would reasonably expect that same behavior when translated to D. If you *want* them in the same scope in D, you can do that with alias.
Aug 01 2018
next sibling parent bachmeier <no spam.net> writes:
On Thursday, 2 August 2018 at 04:59:52 UTC, Walter Bright wrote:

 The difference is those names are supposedly in different 
 namespaces, given that the code is converted from C++:

     namespace ab { void foo(long); }
     ... lots of code ...
     namespace cd { void foo(int); }

 where the foo()'s do not conflict with each other, and a user 
 would reasonably expect that same behavior when translated to D.
This is a trivial problem to solve. mangle(C++, ab) { void foo(long); } mangle(C++, cd) { void foo(int); } It's certainly not obvious to me why anyone would do that, write foo(3); and then blame you when it doesn't work.
Aug 02 2018
prev sibling parent Rubn <where is.this> writes:
On Thursday, 2 August 2018 at 04:59:52 UTC, Walter Bright wrote:
 On 8/1/2018 7:09 PM, Rubn wrote:
 On Wednesday, 1 August 2018 at 23:04:01 UTC, Walter Bright 
 wrote:
 An example of silent hijacking:

    extern (C++, "ab") void foo(long); // original code
    ... lots of code ...
    extern (C++, "cd") void foo(int); // added later by 
 intern, should have been
                                      //
placed in another 
 module
    ... a thousand lines later ...
    foo(0); // OOPS! now calling cd.foo() rather than 
 ab.foo(), D sux

 You might say "nobody would ever write code like that." But 
 that's like the C folks saying real C programmers won't write:
You can do that today, just remove the "extern(C++, ...)" part and you have the same issue. Why should C++ with namespaces be safer than just regular D ? I don't understand, if it is such a huge gigantic problem why didn't you do anything to solve this problem in regards to D then ?
The difference is those names are supposedly in different namespaces, given that the code is converted from C++: namespace ab { void foo(long); } ... lots of code ... namespace cd { void foo(int); } where the foo()'s do not conflict with each other, and a user would reasonably expect that same behavior when translated to D. If you *want* them in the same scope in D, you can do that with alias.
You can say the same thing in D. If you have "module ab" and "module cd", if you put the function in the wrong file, you will face this same bug. It's not a hypothetical, it's the current implementation in D, yet no one has complained or filed a bug report about it. The bug is caused by the implicit conversion from int to long. That is not, nor should it be, the purpose of C++ namespaces in D to fix.
Aug 02 2018
prev sibling next sibling parent Johannes Pfau <nospam example.com> writes:
Am Wed, 01 Aug 2018 16:04:01 -0700 schrieb Walter Bright:

 Certainly, it does come across like you didn't trust the D module
 system to do its job for some reason.
Reorganizing the code into modules means potentially forcing users to split code from one C++ file into multiple D files. How's that really going to work if you have a translation tool? One of the aspects of Java I didn't care for was forcing each class into its own file.
Why would that not work with a translation tool? Just establish a fixed C+ + namespace / D module mapping, then whenever processing something in a C+ + namespace append the declaration to the corresponding file.
 
 So while Manu is clearly happy with cutting up a C++ file into multiple
 D files,
 I doubt that is universal. His proposal would pretty much require that
 for anyone trying to work with C++ namespaces who ever has a name
 collision/hijack or wants to make the code robust against
 collision/hijacking.
 
 An example of silent hijacking:
 
     extern (C++, "ab") void foo(long); // original code ... lots of code
     ...
     extern (C++, "cd") void foo(int); // added later by intern, should
     have been
                                       // placed in another module
     ... a thousand lines later ...
     foo(0); // OOPS! now calling cd.foo() rather than ab.foo(), D sux
 
 You might say "nobody would ever write code like that." But that's like
 the C folks saying real C programmers won't write:
 
      int a[10];
      for (int i = 0; i <= 10; ++i)
         ...a[i]...
 
 But we both know they do just often enough for it to be a disaster.
 
 Now, with D:
 
      extern (C++, ab) void foo(long);
      foo(0);    // works!
      ---
      extern (C++, ab) void foo(long);
      extern (C++, ab) void foo(int);   // error!
      ---
      extern (C++, ab) void foo(long);
      extern (C++, cd) void foo(int);
      foo(0);    // error!
 
 I juxtaposed the lines so it's obvious. It's not so obvious when there's
 a thousand lines of code between each of those lines. It's even worse
 when foo(long) sends a birthday card to your daughter, and foo(int)
 launches nuclear missiles.
If you insist on using a 'translator' tool anyway, it's trivial to detect this problem automatically in such a tool. -- Johannes
Aug 01 2018
prev sibling next sibling parent Johannes Pfau <nospam example.com> writes:
Am Wed, 01 Aug 2018 16:04:01 -0700 schrieb Walter Bright:

 
 Now, with D:
 
      extern (C++, ab) void foo(long);
      foo(0);    // works!
      ---
      extern (C++, ab) void foo(long);
      extern (C++, ab) void foo(int);   // error!
      ---
      extern (C++, ab) void foo(long);
      extern (C++, cd) void foo(int);
      foo(0);    // error!
 
 I juxtaposed the lines so it's obvious. It's not so obvious when there's
 a thousand lines of code between each of those lines. It's even worse
 when foo(long) sends a birthday card to your daughter, and foo(int)
 launches nuclear missiles.
You probably didn't completely think this through: Earlier you suggested to use aliases to avoid explicitly specifying the c++ scopes. Then you suggested to use mixins or translator tools to automate alias generation and avoiding manually writing that boiler plate code. But if you do that: ------------------------- extern (C++, ab) void foo(long); extern (C++, cd) void foo(int); alias foo = ab.foo; alias foo = cd.foo; ------------------------- You've now got exactly the same problem with hijacking... So the benefit of explicit c++ namespace scoping is only a benefit if you do not use this alias trick. But then you face all other problems mentioned earlier... As a result, everybody now has to use the aliasing trick, the hijacking problem still exists and we have to write lots of useless boilerplate. -- Johannes
Aug 01 2018
prev sibling next sibling parent rjframe <dlang ryanjframe.com> writes:
On Wed, 01 Aug 2018 16:04:01 -0700, Walter Bright wrote:

 On 8/1/2018 10:24 AM, Jonathan M Davis wrote:
 Not to say that that can't work, but I have to say that it seems pretty
 ugly if using extern(C++, NS) requires a bunch of aliases just to use
 symbols normally.
What is normal is a slippery concept, especially when one is comparing different lookup rules between languages. D modules do not a 1:1 correspondence with C++ namespaces, either (not even close).
Disclaimer: no knowledge or experience to back up my assumptions: This is the part of the discussion I don't understand. Why do we need to care about [all of the] C++ lookup rules? Even if the D compiler has to know about them, I'd think it's an implementation detail on the D side that wouldn't necessarily need to be passed to the user. If the goal is to link with C++ object files, the only thing that matters is what's available in those files, right? Anything to do with C++ rules that doesn't achieve this goal seems like it's just noise to me.
Aug 02 2018
prev sibling next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/1/18 7:04 PM, Walter Bright wrote:
 On 8/1/2018 10:24 AM, Jonathan M Davis wrote:
 Not to say that that can't work, but I have to say that it seems 
 pretty ugly
 if using extern(C++, NS) requires a bunch of aliases just to use symbols
 normally.
What is normal is a slippery concept, especially when one is comparing different lookup rules between languages. D modules do not a 1:1 correspondence with C++ namespaces, either (not even close). Aliases are a normal and highly useful D tool to copy names from one scope to another.
 Certainly, it does come across like
 you didn't trust the D module system to do its job for some reason.
Reorganizing the code into modules means potentially forcing users to split code from one C++ file into multiple D files. How's that really going to work if you have a translation tool? One of the aspects of Java I didn't care for was forcing each class into its own file. So while Manu is clearly happy with cutting up a C++ file into multiple D files, I doubt that is universal. His proposal would pretty much require that for anyone trying to work with C++ namespaces who ever has a name collision/hijack or wants to make the code robust against collision/hijacking. An example of silent hijacking:    extern (C++, "ab") void foo(long); // original code    ... lots of code ...    extern (C++, "cd") void foo(int); // added later by intern, should have been                                      // placed in another module    ... a thousand lines later ...    foo(0); // OOPS! now calling cd.foo() rather than ab.foo(), D sux You might say "nobody would ever write code like that." But that's like the C folks saying real C programmers won't write:     int a[10];     for (int i = 0; i <= 10; ++i)        ...a[i]... But we both know they do just often enough for it to be a disaster.
I challenge you to find any C++ code that has two identical function names in the same header file, but in different namespaces. I've done C++ development, but not really a C++ developer since about 2010 or so, but to me, this sounds like utter stupidity to do that. I think most of the issue with name conflict is between different *projects*, which is why you have a namespace to begin with. In other words, libfoo defines foo, and libbar defines foo (how dare they!) and now there is a conflict, but you can distinguish by using foo::foo, and bar::foo. But it would be no different in D, since they would be in different libraries anyway, not in the same module. I think comparing that to the <= problem is like apples and oranges. While the problem you identify *is* a problem, I believe it only exists on this thread, and not anywhere else. -Steve
Aug 02 2018
prev sibling parent reply Manu <turkeyman gmail.com> writes:
On Wed, 1 Aug 2018 at 16:05, Walter Bright via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 8/1/2018 10:24 AM, Jonathan M Davis wrote:
 Not to say that that can't work, but I have to say that it seems pretty ugly
 if using extern(C++, NS) requires a bunch of aliases just to use symbols
 normally.
What is normal is a slippery concept, especially when one is comparing different lookup rules between languages. D modules do not a 1:1 correspondence with C++ namespaces, either (not even close). Aliases are a normal and highly useful D tool to copy names from one scope to another.
 Certainly, it does come across like
 you didn't trust the D module system to do its job for some reason.
Reorganizing the code into modules means potentially forcing users to split code from one C++ file into multiple D files. How's that really going to work if you have a translation tool? One of the aspects of Java I didn't care for was forcing each class into its own file. So while Manu is clearly happy with cutting up a C++ file into multiple D files, I doubt that is universal. His proposal would pretty much require that for anyone trying to work with C++ namespaces who ever has a name collision/hijack or wants to make the code robust against collision/hijacking. An example of silent hijacking: extern (C++, "ab") void foo(long); // original code ... lots of code ... extern (C++, "cd") void foo(int); // added later by intern, should have been // placed in another module ... a thousand lines later ... foo(0); // OOPS! now calling cd.foo() rather than ab.foo(), D sux You might say "nobody would ever write code like that." But that's like the C folks saying real C programmers won't write: int a[10]; for (int i = 0; i <= 10; ++i) ...a[i]... But we both know they do just often enough for it to be a disaster. Now, with D: extern (C++, ab) void foo(long); foo(0); // works! --- extern (C++, ab) void foo(long); extern (C++, ab) void foo(int); // error! --- extern (C++, ab) void foo(long); extern (C++, cd) void foo(int); foo(0); // error! I juxtaposed the lines so it's obvious. It's not so obvious when there's a thousand lines of code between each of those lines. It's even worse when foo(long) sends a birthday card to your daughter, and foo(int) launches nuclear missiles. Yes, this extra protection comes at a cost - you'll have to type a bit more. Just like D doesn't allow implicit declaration of variables, requires static typing, and variables are always initialized unless you explicitly use `= void`. The protection is worth it, and is part of D's philosophy. I hope that adequately answers the "for some reason" :-)
I'm sorry, that doesn't come remotely close justifying the imbalance. Firstly, it remains entirely hypothetical, whereas our criticisms are evidence based, over more than half a decade. "D modules do not a 1:1 correspondence with C++ namespaces, either (not even close)." - exactly. So don't even try to emulate C++'s broken feature in D. We can't win; equivalent semantics are impossible, we only get the *worst* of both worlds by trying. "Reorganizing the code into modules means potentially forcing users to split code from one C++ file into multiple D files" - Yes, that is what people do when binding C++ code. We're not writing C++ code, we're writing D code, intended to be consumed by other D code, playing by D's rules. We just want to be able to call functions that are in some C++ .obj file, and get on with writing our D code. To make a C++ API comfortable and natural to a D user, in all but the simplest cases, it has required such human intervention in all meaningful case I've attempted so far, if you want a quality result. I'm not interested in mediocre results; that does nothing but damage the impression D makes on C++ users, and thereby wasting my time and effort, and undermining the potential advance of D to a target group of interested new users. "So while Manu is clearly happy with cutting up a C++ file into multiple D files, I doubt that is universal" - support this claim? I'm happy with doing what is necessary to make a C++ API express as naturally as possible to D code. I would expect most people making such an effort to feel the same way. Why would you suspect otherwise? But then also take that in conjunction with the fact that I haven't actually argued for the demolition of the C++ namespace scope (I don't care either way). It can stay and resolve these hypotheticals if you must, although my bias is that the namespace should be applicable by some other opt-in mechanism. But I'm not interested in pushing that, I have no horse in that race. You can keep your namespace. But don't ruin C++ interaction for the rest of us! "How's that really going to work if you have a translation tool?" - that sounds like a job that's 100 times simpler for a tool than for a human! That said, I have dabbled with such machine translation, and it's non-trivial in a whole variety of ways. This issue you describe is trivial by comparison to the real challenges; C++ and D are not the same language, and they express differently. Lots of C++ constructs don't have a perfect translation and need user intervention of one kind or another. Purely tool translated API's are likely to be poor-quality API's in D. Lots of supporting machinery (macros, helper templates, etc) outside of the hard symbols that you link against need to be massaged by hand for natural D consumption. Atila has done much more work on this, and this thread is evidence that he's also been aggravated by this issue. He may have been able to work-around, but we have wasted his time here, and nobody is any better-off for it. Your machine translation argument does not appear to track reality. "Yes, this extra protection comes at a cost - you'll have to type a bit more." - ignoring that this is 100% dismissive of every complaint ever arisen... this isn't always possible. "Typing" isn't a feature of generative programming, where the case must be detected and manually accounted in the generational logic, which I do heaps of. A mixin placed inside a namespace scope is incapable of also introducing a matching alias outside of the scope. The acrobatics requires to make this work undermine the value. And this claim "The protection is worth it" - that is so much more subjective than anything you've ever criticised me for saying, because it flies in the face of all the evidence we've ever collected. Your examples with multiple sibling namespaces in the same file are borderline contrived. I've never seen sibling namespaces in a single file. It's theoretically possible, but you can't balance the value against the costs on the merit of that point with a straight face. Occasionally there's some nested 'internal' namespace, and that maps perfectly naturally to a submodule, or much better, lifted to private or package protection at module scope. 'internal' or 'detail' namespaces are a symptom of C++ not having such a feature, and it's mostly not desirable to mirror them in D. If you don't like that, you have previously suggested solutions where we use an alternative construct like a struct for namespacing. But if you genuinely feel a within-a-single-module namespace solution is useful, then that should be a separate proposal that stands on its own. It should also be opt-in. I would still find no reason to deviate from the simplicity of arranging namespaces via D modules, in a completely conventional, consistent, and proven manner. The current design denies us this most simple of options. If that's the substance of the protective measures provided, then that's a very poor balance against the problems. Design should encourage maximum simplicity, not maximum complexity as it does.
Aug 04 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/4/2018 12:45 AM, Manu wrote:
 [...]
I get it, Manu, you don't find my arguments compelling. You've put these forth before, and I could repeat myself rebutting each. I expect we're at a dead end with that. But the fact remains, I've shown both you and Atila how to make things work for you, in a hygienic manner, with the language as it is now. For you, it's adding an alias declaration. For Atila, it's a couple lines of boilerplate dpp can add, without disrupting dpp's internal design. I understand you don't want to type in the alias declaration. May I suggest using Atila's dpp? Then you won't have to even look at the output. I also expect that your use cases can help make dpp better, and that would be good for all of us. --- P.S. I have no experience with dpp and how it is used. But my experience with translators is that nobody expects to nor wants to look at its output. They just want it to work. And it seems a fact of life that the output of machine translation resists being purty, because what's purty in A never looks purty in B.
Aug 05 2018
next sibling parent reply Manu <turkeyman gmail.com> writes:
On Sun, 5 Aug 2018 at 16:30, Walter Bright via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 8/4/2018 12:45 AM, Manu wrote:
 [...]
I get it, Manu, you don't find my arguments compelling. You've put these forth before, and I could repeat myself rebutting each. I expect we're at a dead end with that.
So, what you're saying is "I hear you, and I will never change it because I subjectively prefer it the way it is in spite of every users experience". Will you commit to that position officially, so we can refer back to it in future? Just support the string namespace? It won't hurt you, our code will be better, and you'll make us all that actually link to C++ so much happier for it. If we produce a DIP to fix this, will you reject it in principle?
Aug 05 2018
next sibling parent 12345swordy <alexanderheistermann gmail.com> writes:
On Monday, 6 August 2018 at 04:53:05 UTC, Manu wrote:

 If we produce a DIP to fix this, will you reject it in 
 principle?
I think you and Walter Bright made good points and I think a creation of a DIP that addresses his concerns would be a best course of action IMO. -Alexander
Aug 06 2018
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/5/2018 9:53 PM, Manu wrote:
 If we produce a DIP to fix this, will you reject it in principle?
Producing a DIP is a good idea, it provides an anchor point for any future discussion of the topic, rather than the tangle and noise that is this thread. It is an ample opportunity to put the best foot forward on your ideas. I'm not going to categorically say we'll reject it, but will say that you'll need to make a more compelling case, and a DIP is the right method for that. Please keep in mind that a good DIP will address the counterarguments and other methods of solving the issue. As this thread affirms, trying to design things in the forums doesn't work very well, and I should have asked for a DIP in the first place.
Aug 06 2018
prev sibling next sibling parent reply Danni Coy <danni.coy gmail.com> writes:
Outside perspective here and possibly stupid question. Is there any way we
could have our cake and eat it too? One of the thinks I like is that it
tends to be much more readable than C++, more code than necessary hurts
readability of  that code. Can the compiler warn when a function is called
that is shadowed by another function in a different namespace. This to me
seems like the most sane solution, what am I missing?

On Mon, Aug 6, 2018, 14:53 Manu via Digitalmars-d <
digitalmars-d puremagic.com> wrote:

 On Sun, 5 Aug 2018 at 16:30, Walter Bright via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 On 8/4/2018 12:45 AM, Manu wrote:
 [...]
I get it, Manu, you don't find my arguments compelling. You've put these
forth
 before, and I could repeat myself rebutting each. I expect we're at a
dead end
 with that.
So, what you're saying is "I hear you, and I will never change it because I subjectively prefer it the way it is in spite of every users experience". Will you commit to that position officially, so we can refer back to it in future? Just support the string namespace? It won't hurt you, our code will be better, and you'll make us all that actually link to C++ so much happier for it. If we produce a DIP to fix this, will you reject it in principle?
Aug 06 2018
parent bachmeier <no spam.net> writes:
On Monday, 6 August 2018 at 09:48:30 UTC, Danni Coy wrote:
 Outside perspective here and possibly stupid question. Is there 
 any way we could have our cake and eat it too? One of the 
 thinks I like is that it tends to be much more readable than 
 C++, more code than necessary hurts readability of  that code. 
 Can the compiler warn when a function is called that is 
 shadowed by another function in a different namespace. This to 
 me seems like the most sane solution, what am I missing?
I haven't read all of the posts in this thread, but my understanding of Walter's argument is that he believes there is only one correct way to work with C++ code. If that's the case, there's no need for warnings, because the language should prevent you from doing it wrong in the first place. The first step will be to convince him that the "mangle only" approach is valid.
Aug 06 2018
prev sibling parent reply tide <tide tide.tide> writes:
On Sunday, 5 August 2018 at 23:28:06 UTC, Walter Bright wrote:
 On 8/4/2018 12:45 AM, Manu wrote:
 [...]
I get it, Manu, you don't find my arguments compelling. You've put these forth before, and I could repeat myself rebutting each. I expect we're at a dead end with that. But the fact remains, I've shown both you and Atila how to make things work for you, in a hygienic manner, with the language as it is now. For you, it's adding an alias declaration. For Atila, it's a couple lines of boilerplate dpp can add, without disrupting dpp's internal design.
What's your crossplatform workaround if I have a namespace named "version" or "package" ? extern(C++, version) // error { void foo(); } extern(C++, package) // error { void bar(); } You also didn't mention your reasoning behind not including a way to use const pointers to mutable data. The only workaround that exists currently is to rewrite C++ code, which you stated wasn't a valid solution you considered for extern(C++).
 I understand you don't want to type in the alias declaration. 
 May I suggest using Atila's dpp? Then you won't have to even 
 look at the output. I also expect that your use cases can help 
 make dpp better, and that would be good for all of us.

 ---

 P.S. I have no experience with dpp and how it is used. But my 
 experience with translators is that nobody expects to nor wants 
 to look at its output. They just want it to work. And it seems 
 a fact of life that the output of machine translation resists 
 being purty, because what's purty in A never looks purty in B.
How can you suggest DPP then go on to say you've never even used it or know how it is even used?
Aug 06 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/6/2018 11:26 AM, tide wrote:
 What's your crossplatform workaround if I have a namespace named "version" or 
 "package" ?
See my reply to Rick Cattermole. https://digitalmars.com/d/archives/digitalmars/D/Is_there_any_good_reason_why_C_namespaces_are_closed_in_D_317277.html#N317507
 You also didn't mention your reasoning behind not including a way to use const 
 pointers to mutable data.
That's a longstanding issue and has nothing to do with namespaces.
 How can you suggest DPP then go on to say you've never even used it or know
how 
 it is even used?
Because I have full confidence in Atila and Laeeth. I've also written such a translator myself (HTOD) so I know what they're capable of.
Aug 06 2018
parent reply tide <tide tide.tide> writes:
On Monday, 6 August 2018 at 20:35:37 UTC, Walter Bright wrote:
 On 8/6/2018 11:26 AM, tide wrote:
 What's your crossplatform workaround if I have a namespace 
 named "version" or "package" ?
See my reply to Rick Cattermole. https://digitalmars.com/d/archives/digitalmars/D/Is_there_any_good_reason_why_C_namespaces_are_closed_in_D_317277.html#N317507
But that's not currently implemented is it? Your proposed solution adds an exception to the rule that just increases complexity of the language. No where else does "__" remove itself from the name it is used with. With the syntax extern(C++, "...") it is more easily understood, no crazy exceptions need to be made.
 You also didn't mention your reasoning behind not including a 
 way to use const pointers to mutable data.
That's a longstanding issue and has nothing to do with namespaces.
That's just a deflection, we are talking about C++ name mangling, not namespaces. How do you mangle const pointers to mutable data in D to be able to call C++ ? You don't need to implement the feature, you just need a way to create the C++ mangle, which there is none. The only way is to change C++ code, like you said, telling people to rewrite their code is never, ever going to work.
Aug 06 2018
parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/6/2018 3:19 PM, tide wrote:
 That's just a deflection,
1. I'm only here to help, and am not interested in scoring debate points. 2. To bring up other topics, please start a new thread. Especially since this one is quite voluminous.
Aug 06 2018
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
On Wed, 1 Aug 2018 at 10:25, Jonathan M Davis via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Wednesday, August 1, 2018 4:02:39 AM MDT Walter Bright via Digitalmars-d
 wrote:
 On 7/31/2018 1:12 AM, Manu wrote:
 Given your favourite example:
 ----
 module a;
 extern(C++, ns) void foo();
 ----
 module b;
 extern(C++, ns) void foo();
 -----
 module c;
 import a, b;
 foo(); // error: ambiguous
 ns.foo(); // error, ambiguous (obviously)
 a.ns.foo(); // naturally, this works... it's the D module that
 correctly organises the symbol. 'ns' is worthless here
You can write it like this: ---- module a; extern(C++, ns) void foo(); alias foo = ns.foo; ---- module b; extern(C++, ns) void foo(); alias foo = ns.foo; ----- import a,b; a.foo(); // calls a.ns.foo() b.foo(); // calls b.ns.foo()
Not to say that that can't work, but I have to say that it seems pretty ugly if using extern(C++, NS) requires a bunch of aliases just to use symbols normally. If the namespace were just part of the mangling, none of those aliases would be necessary. All in all, it just seems like having the namespaces add scoping just gets in the way - especially when they would normally get the necessary scoping from being put into separate D modules. Reading through this thread, and thinking about the issue, I don't see any advantage to the current behavior over having it just affect mangling other than the fact that that's how it currently works. All of the potential complaints that you talk about seem like they at least _should_ be a non-issue given that folks don't complain that way about D's module system for non-C++ functions - but it's certainly true that even engineers aren't always logical or reasonable. However, if we were discussing a DIP for implementing namespaces for C++, based on my current understanding of the matter, I'd definitely argue that extern(C++) with namespaces should just affect mangling, since that approach seems much more straightforward and much more in line with how other languages are handled, particularly since the scoping aspect is already going to be handled by D's module system anyway. As it stands, it just seems like the language is forcing that all C++ functions be put inside of structs to namespace them on top of them being put into a module. And that's downright awkward, even if it can work. Certainly, it does come across like you didn't trust the D module system to do its job for some reason.
Thank you Jonathan.
Aug 01 2018
prev sibling parent reply Manu <turkeyman gmail.com> writes:
On Wed, 1 Aug 2018 at 03:05, Walter Bright via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 Was that a deliberate
 strategy? I feel like that strategy's been used before.
You repeatedly impugn my motives and/or my mental stability. While that doesn't bother me, it really does not help your case.
I'm not quite sure this is a fair connection... or certainly that's not my intent. But I do struggle to understand how our arguments about the pointlessness of this complexity are so easy to dismiss, without providing any substance at all, ever, in support of the design as is. I can't accept workarounds involving manual intervention when the problem shouldn't exist in the first place. This is busy-work which we will continue to do ad-infinitum, and every time it occurs I just get more upset and unreasonable.
 Please just stick to the technical issue.
That ball's in your court. You've never justified the design complexity and the baggage it carries. I've prompted such justification maybe 5 times in this thread already. This isn't a technical debate. It never has been. If it was, we would have arrived at "C++ namespaces are just for mangling" 6 years ago. The evidence can't lead to any other conclusion.
 Believe it or not, I really want to help you (and Laeeth and Atila) be
successful with this.
Then listen to us. There's a blindingly obvious and ultimately simplifying solution. It will literally resolve _every single case_ of issue or friction or complaint i'm aware of that that has ever emerged regarding C++ namespace mangling. It has never demonstrated to be useful, and we have never identified a single issue that would be created in the process. This entire class of problem will instantly disappear. And it's not even a breaking change (ie, allow string, and then we can even solve the additional problem where we can't refer to D reserved names/keywords). Unless there are actually technical reasons to wear this complexity, recommendations including "use alias everywhere", or "put everything in one file" will never satisfy.
Aug 01 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/1/2018 12:01 PM, Manu wrote:
 You've never justified the design
 complexity and the baggage it carries.
Don't confuse you not agreeing with it with I never justified it. And please don't confuse me not listening to you with me not agreeing with you. It *is* possible for reasonable people to disagree, especially when any solution will involve many tradeoffs and compromises.
Aug 01 2018
next sibling parent Johannes Pfau <nospam example.com> writes:
Am Wed, 01 Aug 2018 22:13:05 -0700 schrieb Walter Bright:

 On 8/1/2018 12:01 PM, Manu wrote:
 You've never justified the design complexity and the baggage it
 carries.
Don't confuse you not agreeing with it with I never justified it. And please don't confuse me not listening to you with me not agreeing with you. It *is* possible for reasonable people to disagree, especially when any solution will involve many tradeoffs and compromises.
In your most recent posts you provided some rationale for this, but nowhere as much as would have been necessary if anybody else proposed this feature and had to write a DIP for it. Introducing c++ namespace scopes added quite some complexity to the language and so far, you seem to be the only proponent of this, whereas we have many opponents. In the DIP process, such a change would have required quite a solid justification, examples, comparison to alternative solutions etc. Such a detailed rationale has never been given for this feature. -- Johannes
Aug 01 2018
prev sibling parent reply Manu <turkeyman gmail.com> writes:
On Wed, 1 Aug 2018 at 22:15, Walter Bright via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 8/1/2018 12:01 PM, Manu wrote:
 You've never justified the design
 complexity and the baggage it carries.
Don't confuse you not agreeing with it with I never justified it. And please don't confuse me not listening to you with me not agreeing with you. It *is* possible for reasonable people to disagree, especially when any solution will involve many tradeoffs and compromises.
We have demonstrated consistent ongoing issues and frustration for 6 years. Your counter-argument is hypothetical at best, and has never demonstrated an advantage. Can you agree on that? I don't think that's a subjective quantity where reasonable people may disagree. If the namespace is useful in a minor subset of cases in the way you argue, then it should be a secondary feature which can be deployed independently as appropriate. It should not be conflated into a basic mangling request which we can't opt-out of. We are yet to observe a case where it was useful, and we have to do ongoing work to try and un-do the effect on our code. I also want to stress, I'm not trying to change the existing code. I'm not for a breaking change. I think implementing the string alternative is the only robust way forward, because that also solves the additional problem of being able to name C++ namespaces that are invalid D keywords, which has bitten me in at least 2 particularly noteworthy occasions. Your hypothetical scenario may continue to be served if you like.
Aug 01 2018
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/1/2018 11:08 PM, Manu wrote:
 I think implementing the string alternative is the only robust way
 forward, because that also solves the additional problem of being able
 to name C++ namespaces that are invalid D keywords, which has bitten
 me in at least 2 particularly noteworthy occasions.
Which keywords were those? In any case, this is a general problem when dealing with C and C++ interoperability, and your solution would only deal with one case of it. For example, --- C++ --- void with(); int scope; enum pure; ----------- If this problem were to be solved, it should be solved, not hacked for one case only. There are many ways of dealing with it: 1. pragma(mangle) 2. change the names in the C/C++ side 3. use a macro -Dwith=with_ when compiling the C/C++ code 4. write wrappers/forwarders/trampolines in C/C++, compile them and link them in 5. write a tool that patches the object file (not as hard as it sounds, the symbol table is usually in one spot, but of course the patcher would have to be implemented for each object file format). I've written object file patchers before, they work surprisingly well. Nobody else does it, presumably because the thought inspires terror :-) 6. provide some switch to the D compiler to rename A=>B in the object file symbols, though I'd worry such would slow the compiler down 7. perhaps amend the language such that an identifier of the form "__keyword" would appear in the object file as "keyword".
Aug 02 2018
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 02/08/2018 8:59 PM, Walter Bright wrote:
 If this problem were to be solved, it should be solved, not hacked for 
 one case only. There are many ways of dealing with it:
 
 1. pragma(mangle)
 
 2. change the names in the C/C++ side
 
 3. use a macro -Dwith=with_ when compiling the C/C++ code
 
 4. write wrappers/forwarders/trampolines in C/C++, compile them and link 
 them in
 
 5. write a tool that patches the object file (not as hard as it sounds, 
 the symbol table is usually in one spot, but of course the patcher would 
 have to be implemented for each object file format). I've written object 
 file patchers before, they work surprisingly well. Nobody else does it, 
 presumably because the thought inspires terror :-)
 
 6. provide some switch to the D compiler to rename A=>B in the object 
 file symbols, though I'd worry such would slow the compiler down
 
 7. perhaps amend the language such that an identifier of the form 
 "__keyword" would appear in the object file as "keyword".
8. if any identifier starts with a keyword and ends with at minimum one _, one _ from the end of the identifier will be removed for mangling (but not e.g. lookup).
Aug 02 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/2/2018 2:05 AM, rikki cattermole wrote:
 8. if any identifier starts with a keyword and ends with at minimum one _, one
_ 
 from the end of the identifier will be removed for mangling (but not e.g.
lookup).
This will break existing code. A double underscore prefix is reserved for the implementation, which is why I went down that path.
Aug 02 2018
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 03/08/2018 9:12 AM, Walter Bright wrote:
 On 8/2/2018 2:05 AM, rikki cattermole wrote:
 8. if any identifier starts with a keyword and ends with at minimum 
 one _, one _ from the end of the identifier will be removed for 
 mangling (but not e.g. lookup).
This will break existing code. A double underscore prefix is reserved for the implementation, which is why I went down that path.
Because it will affect mangling only, do we have any examples of c/c++ code that appends _'s to it that is used by the D community?
Aug 02 2018
parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/2/2018 5:23 PM, rikki cattermole wrote:
 Because it will affect mangling only, do we have any examples of c/c++ code
that 
 appends _'s to it that is used by the D community?
The __ scheme won't break existing code, and we don't need a survey to show that.
Aug 05 2018
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/1/2018 11:08 PM, Manu wrote:
 We have demonstrated consistent ongoing issues and frustration for 6
 years.
Have you ever tried the alias method I proposed?
Aug 02 2018
parent reply Manu <turkeyman gmail.com> writes:
On Thu, 2 Aug 2018 at 02:05, Walter Bright via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 8/1/2018 11:08 PM, Manu wrote:
 We have demonstrated consistent ongoing issues and frustration for 6
 years.
Have you ever tried the alias method I proposed?
Of course, it's the only tool we have here, and a major source of my frustration! Every time I type alias this way, I have thoughts that make baby Jesus cry.
Aug 02 2018
parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/2/2018 9:58 AM, Manu wrote:
 Have you ever tried the alias method I proposed?
Of course, it's the only tool we have here, and a major source of my frustration!
Why is it frustrating?
Aug 02 2018
prev sibling parent Mathias Lang <pro.mathias.lang gmail.com> writes:
On Tuesday, 31 July 2018 at 06:12:40 UTC, Walter Bright wrote:
 Thirdly, C and C++ are loaded to the gills with 
 seemed-like-a-good-idea-at-the-time solutions that turned out 
 to have bad unintended consequences that bork up the language 
 for everyone down the line. D has some of those, too.
And only experience can tell if those ideas turn out to be bad, as people make use of it and realize how (im)practical they are. We only got a handful known serious users of `extern (C++)` on Windows, and probably only me on POSIX (because anything templated doesn't mangle properly on POSIX, so the STL is unusable). So if all users come together to say that the current design seemed-like-a-good-idea-at-the-time (to you) but is not, and could be *simplified* to yield a better product, it sounds very backward to not listen to them.
Jul 31 2018
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Monday, 30 July 2018 at 20:23:25 UTC, Walter Bright wrote:
 On 7/30/2018 9:45 AM, Manu wrote:
 Sure it 'works', but it's an annoying point of friction, and it
 doesn't need to be that way.
You can reduce it to: mixin(cppNamespace("ns", "void foo();"));
 You haven't explained why you can't just move the namespace 
 ns declarations in
 one file together.
Are you serious?
Yes, please explain why you can't coalesce the namespace declarations in one C++ file into one namespace declaration.
Because one C++ file != one C++ translation unit. All of them will #include other files and need the symbols in them, which, for anything using namespaces (the standard library, boost, ...), will mean several instances of opening and closing the same namespace. The only good way (I don't think the mixin template and struct solutions count) to link to any of that today would be to have one enormous D file with _everything_ in it, including nested namespaces.
Jul 31 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/31/2018 1:47 AM, Atila Neves wrote:
 The only good way (I don't think the mixin template and struct solutions
count) 
 to link to any of that today would be to have one enormous D file with 
 _everything_ in it, including nested namespaces.
Why doesn't it count? The user doesn't need to write that code, the translator does. It achieves what you ask for - a declaration of foo() in the current scope, with the mangling in the C++ namespace. All it requires from the translator is putting a boilerplate prefix and suffix onto what it already does. I.e., extern (C++, ns) int foo(); becomes: mixin template X() { // boilerplate prefix extern (C++, ns) int foo(); // original line } mixin X!() x; alias foo = x.ns.foo; // boilerplate suffix Of course, you'd also need to write X and x as X with __LINE__ appended so unique symbols are generated. (I know you've had trouble with generating unique names in another post, but that's an independent problem we should find a way to fix. Maybe instead of __LINE__, use a checksum of the original line?)
Aug 01 2018
next sibling parent reply Johannes Pfau <nospam example.com> writes:
Am Wed, 01 Aug 2018 16:31:57 -0700 schrieb Walter Bright:

 On 7/31/2018 1:47 AM, Atila Neves wrote:
 The only good way (I don't think the mixin template and struct
 solutions count)
 to link to any of that today would be to have one enormous D file with
 _everything_ in it, including nested namespaces.
Why doesn't it count? The user doesn't need to write that code, the translator does.
I remember a time when people here were joking about all the boilerplate you have to write when using java and that it's only usable with an IDE. Now we've got a C++ interfacing which requires lots of boilerplate and is only usable with an external translater tool... I guess that would be acceptable if there is a real benefit, but I have not seen a single argument for the current behavior in this thread. It's great that we can workaround the scoping with lots of boilerplate, but when is C++ namespaces introducing a scope in D actually useful? Can you give an example where this scoping is necessary? So far I have not seen a single person happily using that scoping feature. -- Johannes
Aug 01 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/1/2018 10:06 PM, Johannes Pfau wrote:
 I guess that would be acceptable if there is a real benefit, but I have
 not seen a single argument for the current behavior in this thread.
Please read my postings in this thread, then.
Aug 02 2018
parent reply Daniel N <no public.email> writes:
On Thursday, 2 August 2018 at 08:31:28 UTC, Walter Bright wrote:
 On 8/1/2018 10:06 PM, Johannes Pfau wrote:
 I guess that would be acceptable if there is a real benefit, 
 but I have
 not seen a single argument for the current behavior in this 
 thread.
Please read my postings in this thread, then.
I know you have been very patient with explaining this, but I've been trying to read all threads on this topic and I'm still not sure, can you please acknowledge if I understood you correctly or not? Let's use a simple pseudo example? Let's assume we have two different 'any' implementations... The current extern(c++) design allows us to bind to both of them in a single file. cpp_bindings.d extern(c++, std) ...any-definition... extern(c++, boost) ...any-definition... Personally I would never *bind* to two different namespaces in a single file, are there any other additional benefits to the current design which I'm overlooking? With a non-scoped extern(c++) we could simply use two files. cppstd/any.d extern(c++, std) ...any-definition... boost/any.d extern(c++, boost) ...any-definition... My conclusion is that _if_ I understood you correctly, it must mean that in the examples which you have in mind, it is common to *bind* to two namespaces in the same file? Could you give a real-world examples of two namespaces which you would like to mix like that in the same *bindings* file? Is it for instance 'std' and 'std::experimental'?
Aug 02 2018
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/2/18 5:26 AM, Daniel N wrote:
 On Thursday, 2 August 2018 at 08:31:28 UTC, Walter Bright wrote:
 On 8/1/2018 10:06 PM, Johannes Pfau wrote:
 I guess that would be acceptable if there is a real benefit, but I have
 not seen a single argument for the current behavior in this thread.
Please read my postings in this thread, then.
I know you have been very patient with explaining this, but I've been trying to read all threads on this topic and I'm still not sure, can you please acknowledge if I understood you correctly or not? Let's use a simple pseudo example? Let's assume we have two different 'any' implementations... The current extern(c++) design allows us to bind to both of them in a single file. cpp_bindings.d extern(c++, std)   ...any-definition... extern(c++, boost) ...any-definition... Personally I would never *bind* to two different namespaces in a single file, are there any other additional benefits to the current design which I'm overlooking? With a non-scoped extern(c++) we could simply use two files. cppstd/any.d extern(c++, std)   ...any-definition... boost/any.d extern(c++, boost) ...any-definition... My conclusion is that _if_ I understood you correctly, it must mean that in the examples which you have in mind, it is common to *bind* to two namespaces in the same file? Could you give a real-world examples of two namespaces which you would like to mix like that in the same *bindings* file? Is it for instance 'std' and 'std::experimental'?
The example that Walter keeps bringing up is one where the C++ code has 2 namespaces in the same header file. Not only that, but then identically named functions in those namespaces. In that case, a direct translation would cause problems with hijacking in D, where it doesn't in C++ (as long as you don't ever use `using` declarations, or only use one or the other). So the difference from your example is that you're not trying to bind 2 different files with 2 different namespaces into one D module, but you are translating a single C++ header file that's written with the 2 bindings as described. Not std and boost, but ns1 and ns2 inside the same header file, which each have identical symbols. I've never seen it, but it's certainly valid C++ and in the realm of possibility. -Steve
Aug 02 2018
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 03/08/2018 12:24 AM, Steven Schveighoffer wrote:
 The example that Walter keeps bringing up is one where the C++ code has 
 2 namespaces in the same header file. Not only that, but then 
 identically named functions in those namespaces. In that case, a direct 
 translation would cause problems with hijacking in D, where it doesn't 
 in C++ (as long as you don't ever use `using` declarations, or only use 
 one or the other).
 
 So the difference from your example is that you're not trying to bind 2 
 different files with 2 different namespaces into one D module, but you 
 are translating a single C++ header file that's written with the 2 
 bindings as described. Not std and boost, but ns1 and ns2 inside the 
 same header file, which each have identical symbols.
 
 I've never seen it, but it's certainly valid C++ and in the realm of 
 possibility.
 
 -Steve
That's easy to solve. Split into a package, public import each file and alias if required to get each version. It's easy to work around and most importantly, reasonable.
Aug 02 2018
parent Daniel N <no public.email> writes:
On Thursday, 2 August 2018 at 12:30:14 UTC, rikki cattermole 
wrote:
 On 03/08/2018 12:24 AM, Steven Schveighoffer wrote:
 
 I've never seen it, but it's certainly valid C++ and in the 
 realm of possibility.
 
 -Steve
I see, thanks.
 That's easy to solve.

 Split into a package, public import each file and alias if 
 required to get each version.

 It's easy to work around and most importantly, reasonable.
Agreed.
Aug 02 2018
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/2/2018 2:26 AM, Daniel N wrote:
 Personally I would never *bind* to two different namespaces in a single file, 
You'd be amazed at what people do and then set their entire store based on it. If the language spec allows it, people will do it. People will even design their code to require certain bugs in the compiler. (This really blows when you're trying to write a standard compliant C/C++ compiler and you get angry letters from customers about why I'm not supporting some stupid bug in BrandX C++ that they rely on.) One of my favorite stories about this was a company that had a coding style where their comments looked like this: //******** text ********\\ int x; They thought it was marvelous! But what really happens when you've got two line concatenation characters at the end? Is one line concatenated, or two? You have to carefully read the spec to determine which, and it matters because if two are concatenated then the declaration of x vanishes. And BrandX did it wrong, the customer wrote all their code this way, and it all broke with my compiler, and of course it was all my fault. I thought "who in their right mind would write code that way?" At least I could justify myself with BrandX is a buggy compiler, but when the behavior is in the spec, I have no leg to stand on. If we want to support interfacing with C++, we have to support badly written C++, because that is the NORMAL case. Telling them their code is **** and that they should rewrite it in order to work with D is never, ever going to work. Another anecdote - Microsoft MASM in the 80's was full of bugs. I mean full of bugs. When Borland came out with an assembler, it wouldn't work with most of the ASM files out there. They finally had to engineer in what they called "quirks mode" to emulate MASM's bugs. Telling customers to rework their ASM files didn't work for a large company, either.
 are there any other additional benefits to the current design which I'm 
 overlooking?
 
 With a non-scoped extern(c++) we could simply use two files.
Yes. But then you'll have the people who want a 1:1 correspondence with their C++ files and the corresponding D files. I happen to be one of those people, for the ease of maintaining a translation (and for comparing it with the original C++ source code if it is not behaving correctly). Besides, I provided solutions for both Manu's case and Atila's (they are different), which are easier than "simply" breaking things up into multiple files.
 My conclusion is that _if_ I understood you correctly, it must mean that in
the 
 examples which you have in mind, it is common to *bind* to two namespaces in
the 
 same file? Could you give a real-world examples of two namespaces which you 
 would like to mix like that in the same *bindings* file? Is it for instance 
 'std' and 'std::experimental'?
In D it is not allowed to have multiple modules in the same file. This can become deeply entrenched in the way one thinks about programming, to the point where one cannot conceive of doing it other ways, i.e. ways that C++ allows, and that I believe are poor practice, but people do anyway. You can see this in the C++ backend. It is certainly not organized in a module-like manner. (It predates C++ namespaces, so doesn't use them.)
Aug 03 2018
next sibling parent reply Rubn <where is.this> writes:
On Friday, 3 August 2018 at 21:20:37 UTC, Walter Bright wrote:
 On 8/2/2018 2:26 AM, Daniel N wrote:
 Personally I would never *bind* to two different namespaces in 
 a single file,
You'd be amazed at what people do and then set their entire store based on it. If the language spec allows it, people will do it. People will even design their code to require certain bugs in the compiler. (This really blows when you're trying to write a standard compliant C/C++ compiler and you get angry letters from customers about why I'm not supporting some stupid bug in BrandX C++ that they rely on.) One of my favorite stories about this was a company that had a coding style where their comments looked like this: //******** text ********\\ int x; They thought it was marvelous! But what really happens when you've got two line concatenation characters at the end? Is one line concatenated, or two? You have to carefully read the spec to determine which, and it matters because if two are concatenated then the declaration of x vanishes. And BrandX did it wrong, the customer wrote all their code this way, and it all broke with my compiler, and of course it was all my fault. I thought "who in their right mind would write code that way?" At least I could justify myself with BrandX is a buggy compiler, but when the behavior is in the spec, I have no leg to stand on.
A simple regex could have fixed that problem. They dug themselves a hole and if they don't want to support other compiles, then they will be stuck with BrandX.
 If we want to support interfacing with C++, we have to support 
 badly written C++, because that is the NORMAL case. Telling 
 them their code is **** and that they should rewrite it in 
 order to work with D is never, ever going to work.
There seems to be a misunderstanding here, you don't have to rewrite the C++ code. Merely the D code has to be formatted differently. Unless you have some obsession with maintaining 1:1 C++ and D code. Which is not a technical problem, but one of organization. D isn't C++ and trying to do something crazy like make it compatible so that the files are 1:1 is crazy and unachievable. It only causes problems like what we have now. Maintaining a 1:1 correlation isn't on most D users that work with C++ wish list. Hell all of the Derelict libraries don't maintain a 1:1 at all.
 Another anecdote - Microsoft MASM in the 80's was full of bugs. 
 I mean full of bugs. When Borland came out with an assembler, 
 it wouldn't work with most of the ASM files out there. They 
 finally had to engineer in what they called "quirks mode" to 
 emulate MASM's bugs. Telling customers to rework their ASM 
 files didn't work for a large company, either.
The difference is they would have to rework their existing code. If you are writing D source code bindings for your code, then you are essentially writing new code. You don't have to worry about backwards compatibility. Not only that, who do you think even writes bindings for libraries? Most bindings are done by the community for libraries to other languages. How many companies do you know have bindings for their C/C++ libraries for D, that maintains them?
 are there any other additional benefits to the current design 
 which I'm overlooking?
 
 With a non-scoped extern(c++) we could simply use two files.
Yes. But then you'll have the people who want a 1:1 correspondence with their C++ files and the corresponding D files. I happen to be one of those people, for the ease of maintaining a translation (and for comparing it with the original C++ source code if it is not behaving correctly). Besides, I provided solutions for both Manu's case and Atila's (they are different), which are easier than "simply" breaking things up into multiple files.
So why can't you define the same namespace twice in the same module? There was some conflict that didn't allow it to be implemented the same way as in C++ or something right. So why try to imitate C++ in D but fail to do so because D isn't C++. I think it's worse to try to imitate namespaces in D then create these exceptions to rules when you get snagged on a limitation. Imagine someone tried to write a DIP to add namespaces into D. Do you think anything like that would ever be accepted? God damn hell no. That's what modules are for. So why are you trying to implement namespaces in D under the guise of C++ name mangling. What extern(C++) should be used for is allowing you to call C++ code from D, not to be able to format C++ code into D. The only problem you have with breaking code up into multiple files is that it isn't 1:1. That's not a technical problem, it's a problem of conflicting personal opinion. If it's not 1:1, who cares? If some some odd reason you have two namespaces in one file in C++, odds are they are probably separated in that one file anyway. If not and for some reason the the code has multiple namespace definitions smashed together into one file, flip-floping between namespaces. That's not D's problem to fix the project's poor organization method. Modules are a better way of doing things, we shouldn't be promoting C++'s mistakes in D.
 My conclusion is that _if_ I understood you correctly, it must 
 mean that in the examples which you have in mind, it is common 
 to *bind* to two namespaces in the same file? Could you give a 
 real-world examples of two namespaces which you would like to 
 mix like that in the same *bindings* file? Is it for instance 
 'std' and 'std::experimental'?
In D it is not allowed to have multiple modules in the same file. This can become deeply entrenched in the way one thinks about programming, to the point where one cannot conceive of doing it other ways, i.e. ways that C++ allows, and that I believe are poor practice, but people do anyway. You can see this in the C++ backend. It is certainly not organized in a module-like manner. (It predates C++ namespaces, so doesn't use them.)
On Friday, 3 August 2018 at 21:49:53 UTC, Walter Bright wrote:
 I mean `std` should never be part of the fully qualified name
of, for
 instance, `core.stdcpp.exception.std.bad_exception`. It
should just
 be `core.stdcpp.exception.bad_exception` instead.
C++ recognizes that, too, which is why it has "using" declarations. D has the equivalent thing, "alias". You can do things like: import std = core.stdcpp.exception; and then refer to: std.bad_exception or: import exception = core.stdcpp.exception; exception.bad_exception; or whatever works best for one's project. Aliasing and import renaming (which are really just more aliasing) is very capable, and was designed for just these sorts of issues.
Until you want to use more than one module it falls flat on it's face: import std = core.stdcpp.exception; import std = core.stdcpp.vector; // as an example future use // can't have both, error: import "std" conflicts with other import "std" std.bad_exception std.vector!int
Aug 03 2018
parent reply Laeeth Isharc <Laeeth laeeth.com> writes:
On Friday, 3 August 2018 at 22:55:51 UTC, Rubn wrote:
 The difference is they would have to rework their existing 
 code. If you are writing D source code bindings for your code, 
 then you are essentially writing new code. You don't have to 
 worry about backwards compatibility.
Why would you write bindings if the computer can do it for you, better, faster and consistently? That's the idea behind DPP. You can just #include C headers and they will be translated before compile time. This is very helpful with projects like HDF5 that consider it acceptable in a minor release to replace a function with a macro. Wrappers are a bit different. In time C++ will follow.
 Not only that, who do you think even writes bindings for 
 libraries? Most bindings are done by the community for 
 libraries to other languages. How many companies do you know 
 have bindings for their C/C++ libraries for D, that maintains 
 them?
We do for a few things - for other peoples' libraries not our own. But it would be better not to have to write bindings at all.
 damn hell no. That's what modules are for. So why are you 
 trying to implement namespaces in D under the guise of C++ name 
 mangling.
I don't think either Manu or Atila want to be able to sneak in namespaces by the backdoor. They just want to be able easily to control namespace mangling of C++ linkage symbols. What extern(C++) should be used for is allowing you
 to call C++ code from D, not to be able to format C++ code into 
 D. The only problem you have with breaking code up into 
 multiple files is that it isn't 1:1. That's not a technical 
 problem, it's a problem of conflicting personal opinion. If 
 it's not 1:1, who cares? If some some odd reason you have two 
 namespaces in one file in C++, odds are they are probably 
 separated in that one file anyway. If not and for some reason 
 the the code has multiple namespace definitions smashed 
 together into one file, flip-floping between namespaces. That's 
 not D's problem to fix the project's poor organization method.
For automatically translated bindings I think that the request is not unreasonable because there's considerable value in being able to just #include C++ headers as you can already with C headers and just call the C++ code from D. D doesn't have libraries? Well it's got 1500 on code.dlang.org plus C and C++ libraries. What is it you think is missing? That's a good retort! I understand from Atila present choice just makes it a lot more complicated, not impossible.
Aug 03 2018
next sibling parent reply Manu <turkeyman gmail.com> writes:
On Fri, 3 Aug 2018 at 18:50, Laeeth Isharc via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Friday, 3 August 2018 at 22:55:51 UTC, Rubn wrote:
 The difference is they would have to rework their existing
 code. If you are writing D source code bindings for your code,
 then you are essentially writing new code. You don't have to
 worry about backwards compatibility.
Why would you write bindings if the computer can do it for you, better, faster and consistently?
Faster and consistently, sure. But I don't think 'better' is possible.
From my experience, in many cases, C++ really doesn't express well in
D by direct translation. I tend to do significant massaging of the C++ helper material to improve the experience from D. Usually C++ libs have a lot of helper material in the form of macros, little template utilities, inline wrappers, and they can almost always be expressed more nicely in D with some tweaking. I often also insert some additional inline D helpers/wrappers nearby the externs, which help adapt the signatures; ie, apply some attributes, or make a slice-based API that transforms to ptr+len args, maybe implement a range helper, that sort of thing. The goal is to make the API attractive such that a user is compelled to prefer interacting with the lib from D than from C++. C++ namespaces interfere with overload resolution in particular, and that makes this goal harder. It probably depends on your use. If you're just calling a C++ lib, and wrap it up in a box for use in your local code, a machine translation for the API might be fine. I'd call that 'making use of a feature lib'. If you are linking to a lib that is a fundamental part of your application infrastructure, you absolutely must do significant manual work to make the C++ code express nicely to D, otherwise the user-experience interacting with the C++ api from D will be worse than just using C++. If the C++ experience is better than from D, then D experience ceases to exist as no case can be made to prefer D over C++, the project is moot, and I have wasted my time. The D experience must not just be equal to the C++ experience, it must typically be substantially better in a variety of ways, and I have never been able to have such an experience interacting with C++ without making some manual effort towards quality bindings. The current namespace mechanics put SOOO much more strain on that goal than is necessary. One other important feature of quality bindings, is that the binding itself must be readable and maintainable. The binding itself is the very first showcase to C++ programmers of how their API's could be better in D. It must be well organised (like normal D code), and the current situation with boilerplate invading the works is destructive toward that end. Of course, thanks to this namespace situation, when involving with these hideous workarounds, they are usually objectively NOT better in D, and C++ programmers do indeed recognise that immediately.
Aug 04 2018
next sibling parent Laeeth Isharc <Laeeth laeeth.com> writes:
On Saturday, 4 August 2018 at 07:34:49 UTC, Manu wrote:
 On Fri, 3 Aug 2018 at 18:50, Laeeth Isharc via Digitalmars-d 
 <digitalmars-d puremagic.com> wrote:
 On Friday, 3 August 2018 at 22:55:51 UTC, Rubn wrote:
 The difference is they would have to rework their existing 
 code. If you are writing D source code bindings for your 
 code, then you are essentially writing new code. You don't 
 have to worry about backwards compatibility.
Why would you write bindings if the computer can do it for you, better, faster and consistently?
Faster and consistently, sure. But I don't think 'better' is possible.
From my experience, in many cases, C++ really doesn't express 
well in
D by direct translation. I tend to do significant massaging of the C++ helper material to improve the experience from D. Usually C++ libs have a lot of helper material in the form of macros, little template utilities, inline wrappers, and they can almost always be expressed more nicely in D with some tweaking. I often also insert some additional inline D helpers/wrappers nearby the externs, which help adapt the signatures; ie, apply some attributes, or make a slice-based API that transforms to ptr+len args, maybe implement a range helper, that sort of thing. The goal is to make the API attractive such that a user is compelled to prefer interacting with the lib from D than from C++. C++ namespaces interfere with overload resolution in particular, and that makes this goal harder. It probably depends on your use. If you're just calling a C++ lib, and wrap it up in a box for use in your local code, a machine translation for the API might be fine. I'd call that 'making use of a feature lib'. If you are linking to a lib that is a fundamental part of your application infrastructure, you absolutely must do significant manual work to make the C++ code express nicely to D, otherwise the user-experience interacting with the C++ api from D will be worse than just using C++. If the C++ experience is better than from D, then D experience ceases to exist as no case can be made to prefer D over C++, the project is moot, and I have wasted my time. The D experience must not just be equal to the C++ experience, it must typically be substantially better in a variety of ways, and I have never been able to have such an experience interacting with C++ without making some manual effort towards quality bindings. The current namespace mechanics put SOOO much more strain on that goal than is necessary. One other important feature of quality bindings, is that the binding itself must be readable and maintainable. The binding itself is the very first showcase to C++ programmers of how their API's could be better in D. It must be well organised (like normal D code), and the current situation with boilerplate invading the works is destructive toward that end. Of course, thanks to this namespace situation, when involving with these hideous workarounds, they are usually objectively NOT better in D, and C++ programmers do indeed recognise that immediately.
Would it be inaccurate to make a distinction between bindings and wrappers ? It's always going to be less pleasant to call even C bindings from D then an idiomatic D wrapper written on top. But if you have automatically generated bindings then you can put the effort into the wrappers and it's easier to do the latter incrementally. And being able to use a library at all even if slightly unpleasantly without having to pay a big price up front beats having no choice. At least for us the sequencing of cost matters more than the total cost, and the calendar time element of cost to being able to write a passable and useful first version is more important than the pecuniary element. We have many more people who are not C++ programmers but express their ideas in D then we do people who know C++ pretty well. BTW I almost think the D Foundation should organise a library wrapping as a service marketplace ;). Lots of people in the community are open to remote work part or full time. But the cost is in finding the right people and also to some extent supervising and organising the design and work. That could be just another forum in the beginning.
Aug 04 2018
prev sibling parent Atila Neves <atila.neves gmail.com> writes:
On Saturday, 4 August 2018 at 07:34:49 UTC, Manu wrote:
 On Fri, 3 Aug 2018 at 18:50, Laeeth Isharc via Digitalmars-d 
 <digitalmars-d puremagic.com> wrote:
 [...]
Faster and consistently, sure. But I don't think 'better' is possible. [...]
Bindings != wrappers. I agree that wrappers will nearly always need to be written, I'm trying to automate the writing of the declarations needed to link. It should be possible to automate translating everything, but some things will be tricky in C++. std::vector is quite clearly a value type, yet the GNU implementation declares it as a class with protected inheritance from _Vector_base. That's going to be fun...
Aug 06 2018
prev sibling parent reply tide <tide tide.tide> writes:
On Saturday, 4 August 2018 at 01:45:44 UTC, Laeeth Isharc wrote:
 On Friday, 3 August 2018 at 22:55:51 UTC, Rubn wrote:
 The difference is they would have to rework their existing 
 code. If you are writing D source code bindings for your code, 
 then you are essentially writing new code. You don't have to 
 worry about backwards compatibility.
Why would you write bindings if the computer can do it for you, better, faster and consistently?
With the current tools the ones that generate D files to be used aren't very good. They evaluate Macros based on the current implementation, so if there's a define MACHINE_X86 or MACHINE_x64, those macro and #if's will be evaluated based on the current system running the tool instead of generating equivalent version() statements.
 That's the idea behind DPP.  You can just #include C headers 
 and they will be translated before compile time.  This is very 
 helpful with projects like HDF5 that consider it acceptable in 
 a minor release to replace a function with a macro.

 Wrappers are a bit different.

 In time C++ will follow.
I wouldn't call that the same thing as what generally defines a wrapper. It's a different concept that does the work at compiler time. If I remember correctly Clang has something similar, where two languages can call each other once they have been compiled to Clang's intermediate format. Or at least it was something that was being worked on a while ago, never used it though.
 Not only that, who do you think even writes bindings for 
 libraries? Most bindings are done by the community for 
 libraries to other languages. How many companies do you know 
 have bindings for their C/C++ libraries for D, that maintains 
 them?
We do for a few things - for other peoples' libraries not our own. But it would be better not to have to write bindings at all.
It would be, but I don't think it'll ever be 100% and will require manual intervention.
 damn hell no. That's what modules are for. So why are you 
 trying to implement namespaces in D under the guise of C++ 
 name mangling.
I don't think either Manu or Atila want to be able to sneak in namespaces by the backdoor. They just want to be able easily to control namespace mangling of C++ linkage symbols.
Never said they did, but that's what Walter and the current implementation seem to indicate. I'd rather just have extern(C++) be what extern(C++) and extern(D) do, just change the name mangling, not try to emulate some features of namespaces like it currently does.
 What extern(C++) should be used for is allowing you
 to call C++ code from D, not to be able to format C++ code 
 into D. The only problem you have with breaking code up into 
 multiple files is that it isn't 1:1. That's not a technical 
 problem, it's a problem of conflicting personal opinion. If 
 it's not 1:1, who cares? If some some odd reason you have two 
 namespaces in one file in C++, odds are they are probably 
 separated in that one file anyway. If not and for some reason 
 the the code has multiple namespace definitions smashed 
 together into one file, flip-floping between namespaces. 
 That's not D's problem to fix the project's poor organization 
 method.
For automatically translated bindings I think that the request is not unreasonable because there's considerable value in being able to just #include C++ headers as you can already with C headers and just call the C++ code from D. D doesn't have libraries? Well it's got 1500 on code.dlang.org plus C and C++ libraries. What is it you think is missing? That's a good retort! I understand from Atila present choice just makes it a lot more complicated, not impossible.
The only person I've seen that wants this is Walter. I haven't seen anyone else show interest in wanting a 1:1 correlation. It's unreasonable, D isn't C++ nor should it be trying to strive to be C++. Where are const pointers? Where are default constructors for structs that make structs not POD anymore, that changes the calling convention used in C++ (on Windows at least).
Aug 04 2018
next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Saturday, August 04, 2018 12:18:21 tide via Digitalmars-d wrote:
 The only person I've seen that wants this is Walter. I haven't
 seen anyone else show interest in wanting a 1:1 correlation. It's
 unreasonable, D isn't C++ nor should it be trying to strive to be
 C++.
In general, it's easier for maintenance if there's a 1:1 correlation between C/C++ headers and D headers. It makes it easier to update the D files, and it makes it easier to find where something is in the D translation if you're already familiar with the C/C++ version - or if you're reading documentation for the C/C++ version and trying to translate that into what you need to know to use the D version. For the most part, the C bindings in druntime follow the layout of the C headers that they correspond to precisely because doing so is more maintainable and easier to navigate than if the D modules were laid in a hierarchy that followed its own logic instead of trying to emulate the layout of the C headers being translated. In fact, some of the more annoying issues with the C header translations in druntime come from places where the layout of the C headers was not quite followed for one reason or another. So, I'd fully expect most C/C++ binding projects to have a 1:1 correlation between C/C++ headers and D headers, and I don't think that Walter is at all misguided in that respect. That being said, in most cases, such a 1:1 translation would work just fine if we had extern(C++, "NS"), and it just affected name mangling. There would be corner cases where it did not, but they could be worked around even if it meant that in that particular case, you lost the 1:1 translation - but as Steven pointed out, it actually would be pretty straightforward to manually add the kind of namespace wrappers that the language currently forces on you with extern(C++, NS) if we had extern(C++, "NS"). And of course, if we actually ended up with both extern(C++, "NS"), and extern(C++, NS), then you could just use the extern(C++, NS) construct in those corner cases, though ultimately, I think that we'd be better off with just having extern(C++, "NS"). So, I don't think that Walter is being misguided here in terms of how he expects folks to be translating C++ headers. I just think that his concern over some corner cases you get with bad C++ code has caused him to make the current solution for binding to C++ namespaces more complicated than it needs to be. And I don't think that his concerns are misguided either. I just think that he's just blowing them out of proportion given how easy it would be to work around those issues with the solution that Manu wants, whereas the common case suffers with the current solution. - Jonathan M Davis
Aug 04 2018
parent tid3 <tide tide.tide> writes:
On Saturday, 4 August 2018 at 17:54:11 UTC, Jonathan M Davis 
wrote:
 On Saturday, August 04, 2018 12:18:21 tide via Digitalmars-d 
 wrote:
 The only person I've seen that wants this is Walter. I haven't 
 seen anyone else show interest in wanting a 1:1 correlation. 
 It's unreasonable, D isn't C++ nor should it be trying to 
 strive to be C++.
In general, it's easier for maintenance if there's a 1:1 correlation between C/C++ headers and D headers. It makes it easier to update the D files, and it makes it easier to find where something is in the D translation if you're already familiar with the C/C++ version - or if you're reading documentation for the C/C++ version and trying to translate that into what you need to know to use the D version. For the most part, the C bindings in druntime follow the layout of the C headers that they correspond to precisely because doing so is more maintainable and easier to navigate than if the D modules were laid in a hierarchy that followed its own logic instead of trying to emulate the layout of the C headers being translated. In fact, some of the more annoying issues with the C header translations in druntime come from places where the layout of the C headers was not quite followed for one reason or another. So, I'd fully expect most C/C++ binding projects to have a 1:1 correlation between C/C++ headers and D headers, and I don't think that Walter is at all misguided in that respect. That being said, in most cases, such a 1:1 translation would work just fine if we had extern(C++, "NS"), and it just affected name mangling. There would be corner cases where it did not, but they could be worked around even if it meant that in that particular case, you lost the 1:1 translation - but as Steven pointed out, it actually would be pretty straightforward to manually add the kind of namespace wrappers that the language currently forces on you with extern(C++, NS) if we had extern(C++, "NS"). And of course, if we actually ended up with both extern(C++, "NS"), and extern(C++, NS), then you could just use the extern(C++, NS) construct in those corner cases, though ultimately, I think that we'd be better off with just having extern(C++, "NS"). So, I don't think that Walter is being misguided here in terms of how he expects folks to be translating C++ headers. I just think that his concern over some corner cases you get with bad C++ code has caused him to make the current solution for binding to C++ namespaces more complicated than it needs to be. And I don't think that his concerns are misguided either. I just think that he's just blowing them out of proportion given how easy it would be to work around those issues with the solution that Manu wants, whereas the common case suffers with the current solution. - Jonathan M Davis
Alright that's fair but it still isn't ever going to be 1:1. I've done some stuff with C++ that used the fact that including headers is just a copy and paste. So I had header files that didn't have structures defined in them. You would define the structures before the including the header file so that it could be used with multiple different headers. There's no way you are ever going to get a 1:1 mapping of that into D. Let alone remotely similar, it would have to be completely different. It's nice to have but you are never going to achieve a complete 1:1 mapping unless you bring all of C++'s features. Even with the current implementation it doesn't allow multiple namespaces of the same name in the same D module. Yet Walter is hung up on that fact of that one edge case.
Aug 04 2018
prev sibling parent Atila Neves <atila.neves gmail.com> writes:
On Saturday, 4 August 2018 at 12:18:21 UTC, tide wrote:
 On Saturday, 4 August 2018 at 01:45:44 UTC, Laeeth Isharc wrote:
 On Friday, 3 August 2018 at 22:55:51 UTC, Rubn wrote:
 The difference is they would have to rework their existing 
 code. If you are writing D source code bindings for your 
 code, then you are essentially writing new code. You don't 
 have to worry about backwards compatibility.
Why would you write bindings if the computer can do it for you, better, faster and consistently?
With the current tools the ones that generate D files to be used aren't very good. They evaluate Macros based on the current implementation, so if there's a define MACHINE_X86 or MACHINE_x64, those macro and #if's will be evaluated based on the current system running the tool instead of generating equivalent version() statements.
If the D files are to be checked in, then yes, that'd be a problem. If they're not, as is the case with dpp, then... that's actually what you want. dpp: I fought the preprocessor and the preprocessor won.
 It would be, but I don't think it'll ever be 100% and will 
 require manual intervention.
If manual intervention is required, dpp has failed. Some problems will be tricky, especially where the preprocessor is concerned. But a lot of real-life production code works.
Aug 06 2018
prev sibling next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/3/18 5:20 PM, Walter Bright wrote:

 Telling them their code is 
 **** and that they should rewrite it in order to work with D is never, 
 ever going to work.
And that's OK with me. I'm OK with D saying it only supports reasonably written C++ code, and 99% of the C++ community would agree. If that means we lose one "customer" who doesn't use sane namespace practices, then I guess they can stick with C++.
 are there any other additional benefits to the current design which 
 I'm overlooking?

 With a non-scoped extern(c++) we could simply use two files.
Yes. But then you'll have the people who want a 1:1 correspondence with their C++ files and the corresponding D files. I happen to be one of those people, for the ease of maintaining a translation (and for comparing it with the original C++ source code if it is not behaving correctly).
I have to take this to mean that you are someone who wants 1:1 correspondence, and not someone who puts 2 namespaces in the same file with identical symbol names. In either case, I think it's forgivable for D to not be able to completely mimic C++ in every possible manner.
 Besides, I provided solutions for both Manu's case and Atila's (they are 
 different), which are easier than "simply" breaking things up into 
 multiple files.
But the solution is crazy backwards. You should be able to put in weird aliases and namespaces (or even split into multiple modules) if you have really crappy C++ code with namespace issues. Aliases and bizarre mixins shouldn't be the default *just in case* you have crappy code. Note, I can do this to make namespaces if I want to mimic crappy C++ code in the same file (assuming extern(C++, ns) just affects mangling): template _ns() { extern(C++, ns) void foo(int) {} } alias ns = _ns!(); alias foo = ns.foo; // optional template _ns2() { extern(C++, ns2) void foo(int) {} } alias ns2 = _ns2!(); alias foo = ns2.foo; // optional void main() { // foo(1); // ERROR! ns.foo(1); // OK ns2.foo(1); // OK } Why can't we just tell C++ devs who have this horrible situation to do it this way, and leave all the reasonably named namespaces to use the awesome D module system as expected? -Steve
Aug 04 2018
prev sibling next sibling parent tide <tide tide.tide> writes:
On Friday, 3 August 2018 at 21:20:37 UTC, Walter Bright wrote:
 If we want to support interfacing with C++, we have to support 
 badly written C++, because that is the NORMAL case. Telling 
 them their code is **** and that they should rewrite it in 
 order to work with D is never, ever going to work.
On another note, why aren't const pointers to mutable data supported then? Anytime I need to write a wrapper for a function that has a parameter "T* const" I have to rewrite the C++ code cause there's no cross-platform way to mangle and call that function from D. Does this mean you are for const pointers in D now or is trying to make D into C++ unreasonable now ?
Aug 04 2018
prev sibling parent aliak <something something.com> writes:
On Friday, 3 August 2018 at 21:20:37 UTC, Walter Bright wrote:
 Yes. But then you'll have the people who want a 1:1 
 correspondence with their C++ files and the corresponding D 
 files. I happen to be one of those people, for the ease of 
 maintaining a translation (and for comparing it with the 
 original C++ source code if it is not behaving correctly).
This would still be true if current behavior was kept and extern(C++, "ns") or extern(C++, ns, noscope) or something was added though no? Though I do think the string is superior though because then this would actually compile: extern(C++, "shared") { void f(); } It feels the two preferences being mutually exclusive has somehow occupied a lot of this discussion when they are not. Cheers, - Ali
Aug 06 2018
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Wednesday, 1 August 2018 at 23:31:57 UTC, Walter Bright wrote:
 On 7/31/2018 1:47 AM, Atila Neves wrote:
 The only good way (I don't think the mixin template and struct 
 solutions count) to link to any of that today would be to have 
 one enormous D file with _everything_ in it, including nested 
 namespaces.
Why doesn't it count? The user doesn't need to write that code, the translator does. It achieves what you ask for - a declaration of foo() in the current scope, with the mangling in the C++ namespace.
Good point. I thought about it some more and managed to make it work. It's definitely a hack, but since in my case the user won't usually see the generated code anyway it's not too bad. It's far from ideal, though, because I can't alias an entire nested namespace if it's declared twice, i.e. namespace std { namespace chrono { // ... } } namespace std { namespace chrono { } } With your mixin template technique everything ends up in the global namespace of the moduel making the C++ declarations. I would only be able to alias a nested namespace once, since the code below obviously won't work: mixin CppNamespace0!() x; alias chrono = x.std.chrono; mixin CppNamespace1!() y; alias chrono = y.std.chrono; I considered for a while whether or not this would be truly bad, and the more I think about it the more convinced I am that Manu is right and there should be _no_ scoping whatsoever in D regarding C++ namespaces. We have packages and modules, we can use those to put the C++ functions we declare in whatever hierarchy we want. I think that this:
 It's where std::exception goes -> core.stdcpp.exception
 In it, you'll find some extern(C++,std) declarations. The file 
 can be imported as:
    import core.stdcpp.exception;
 or:
    import core.stdcpp.exception : std;
shouldn't even come up, by which I mean `std` should never be part of the fully qualified name of, for instance, `core.stdcpp.exception.std.bad_exception`. It should just be `core.stdcpp.exception.bad_exception` instead. If one wants to create a `core.stdcpp.chrono`, then it's a case of putting `extern(C++, std.chrono)` in that module and mirroring the namespace hierarchy manually. I don't think the extra `std` helps in any way right now, and anyone writing C++ declarations manually has to go through all the trouble of setting up aliases. None of the warts of C++ scope contaminate D this way. Nobody will ever need to know what ADL is. D scoping and overload rules would be applied, and `extern(C++)` declarations with namespaces only mangle. It would be a breaking change. However, I'd be willing to bet real money that anybody that cares about linking to C++ would gladly see their code break because they're probably using workarounds anyway. Atila
Aug 03 2018
next sibling parent Daniel N <no public.email> writes:
On Friday, 3 August 2018 at 10:58:18 UTC, Atila Neves wrote:
 I thought about it some more and managed to make it work. It's 
 definitely a hack, but since in my case the user won't usually 
 see the generated code anyway it's not too bad. It's far from 
 ideal, though, because I can't alias an entire nested namespace 
 if it's declared twice, i.e.
The user will actually see it, because the full name will be in all compilation errors, debugging, reflection etc. I think that's the most annoying part. But it's great that you got it working, that's the first step. :)
Aug 03 2018
prev sibling next sibling parent CommanderZot <no no.no> writes:
On Friday, 3 August 2018 at 10:58:18 UTC, Atila Neves wrote:
 On Wednesday, 1 August 2018 at 23:31:57 UTC, Walter Bright 
 wrote:
 [...]
Good point. [...]
We can also just keep the current behaviour and implement something like extern(C++, "std::chrono") in addition (as manu pointed out multiple times).
Aug 03 2018
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/3/2018 3:58 AM, Atila Neves wrote:
 With your mixin template technique everything ends up in the global namespace
of 
 the moduel making the C++ declarations.
Right, but that's what you wanted!
 I would only be able to alias a nested 
 namespace once, since the code below obviously won't work:
 
     mixin CppNamespace0!() x;
     alias chrono = x.std.chrono;
     mixin CppNamespace1!() y;
     alias chrono = y.std.chrono;
Try this: mixin template X() { // boilerplate prefix extern (C++, std) extern(C++, chrono) int foo(); // original line } mixin X!() x; alias foo = x.std.chrono.foo; // boilerplate suffix
 I considered for a while whether or not this would be truly bad, and the more
I 
 think about it the more convinced I am that Manu is right and there should be 
 _no_ scoping whatsoever in D regarding C++ namespaces. We have packages and 
 modules, we can use those to put the C++ functions we declare in whatever 
 hierarchy we want.
I am puzzled. With: namespace std { namespace chrono { void foo(); } } namespace std { namespace chrono { void bar(); } } you have stated that it is impractical for your translator to rewrite this as: namespace std { namespace chrono { void foo(); void bar(); } } Ok, I get that. But it is practical to rewrite it as: module std.chrono; void foo(); void bar(); ?
 I mean `std` should never be part of the fully qualified name of, for
 instance, `core.stdcpp.exception.std.bad_exception`. It should just
 be `core.stdcpp.exception.bad_exception` instead.
C++ recognizes that, too, which is why it has "using" declarations. D has the equivalent thing, "alias". You can do things like: import std = core.stdcpp.exception; and then refer to: std.bad_exception or: import exception = core.stdcpp.exception; exception.bad_exception; or whatever works best for one's project. Aliasing and import renaming (which are really just more aliasing) is very capable, and was designed for just these sorts of issues.
Aug 03 2018
parent reply Atila Neves <atila.neves gmail.com> writes:
On Friday, 3 August 2018 at 21:49:53 UTC, Walter Bright wrote:
 On 8/3/2018 3:58 AM, Atila Neves wrote:
 I would only be able to alias a nested namespace once, since 
 the code below obviously won't work:
 
     mixin CppNamespace0!() x;
     alias chrono = x.std.chrono;
     mixin CppNamespace1!() y;
     alias chrono = y.std.chrono;
Try this: mixin template X() { // boilerplate prefix extern (C++, std) extern(C++, chrono) int foo(); // original line } mixin X!() x; alias foo = x.std.chrono.foo; // boilerplate suffix
That doesn't solve the problem at all. I was toying with being able to have a nested namespace be an alias in a module. I can't realias chrono after the first `alias chrono = `, nor can I alias it to the different `chrono`s in all the different template mixins.
 I considered for a while whether or not this would be truly 
 bad, and the more I think about it the more convinced I am 
 that Manu is right and there should be _no_ scoping whatsoever 
 in D regarding C++ namespaces. We have packages and modules, 
 we can use those to put the C++ functions we declare in 
 whatever hierarchy we want.
I am puzzled. With: namespace std { namespace chrono { void foo(); } } namespace std { namespace chrono { void bar(); } } you have stated that it is impractical for your translator to rewrite this as: namespace std { namespace chrono { void foo(); void bar(); } } Ok, I get that. But it is practical to rewrite it as: module std.chrono; void foo(); void bar(); ?
I don't understand what your question has to do with what you quoted. What I'm trying to say is that I think `extern(C++, foo.bar)` should NOT introduce a scope in D in any way, shape, or form. The D module/import/overload system should have no idea of what `foo` or `foo.bar` are - they don't exist.
 I mean `std` should never be part of the fully qualified name
of, for
 instance, `core.stdcpp.exception.std.bad_exception`. It
should just
 be `core.stdcpp.exception.bad_exception` instead.
C++ recognizes that, too, which is why it has "using" declarations. D has the equivalent thing, "alias". You can do things like: import std = core.stdcpp.exception; and then refer to: std.bad_exception or: import exception = core.stdcpp.exception; exception.bad_exception; or whatever works best for one's project. Aliasing and import renaming (which are really just more aliasing) is very capable, and was designed for just these sorts of issues.
I think we're talking past each other. I know how to alias in D, and how to use `using` in C++. What I'm saying is that, with the file we have now (core.stdcpp.exception): extern(C++, std) { class exception { /* ... */ } } Currently the fully qualified name of `exception` is `core.stdcpp.exception.std.exception`. I'm arguing that this is a mistake, and the the FQN should instead be `core.stdcpp.exception.exception`. Yes, namespaces introduce scope in C++. Yes, lookup rules in C++ are crazy. The main points I'm (and, I think, Manu) arguing are: 1. We already have D packages, modules, and overload rules. We don't need to import any from C++ 2. That namespaces introduce a scope in C++ does not mean that `extern(C++, ns)` should introduce one in D i.e. Keep everything about D as-is, _except_ for no scoping for `extern(C++, ns)`.
Aug 06 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
Let's see if we can find some common ground.

The boilerplate I suggested seems to enable DPP to generate working code that 
behaves "as if" the namespace scope is not there, even for nested namespaces.

Is this correct?
Aug 06 2018
next sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Tuesday, 7 August 2018 at 02:25:32 UTC, Walter Bright wrote:
 Let's see if we can find some common ground.

 The boilerplate I suggested seems to enable DPP to generate 
 working code that behaves "as if" the namespace scope is not 
 there, even for nested namespaces.

 Is this correct?
Yes, but only for a single instance of the namespace. In the general case no, see the first reply in https://forum.dlang.org/post/xdaedmlbbqtztiqcwxll forum.dlang.org
Aug 06 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/6/2018 8:14 PM, Nicholas Wilson wrote:
 Yes, but only for a single instance of the namespace.
 In the general case no, see the first reply in 
 https://forum.dlang.org/post/xdaedmlbbqtztiqcwxll forum.dlang.org
The idea is to not have a namespace, I don't see what making an alias to a namespace has to do with it.
Aug 06 2018
parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Tuesday, 7 August 2018 at 05:58:17 UTC, Walter Bright wrote:
 On 8/6/2018 8:14 PM, Nicholas Wilson wrote:
 Yes, but only for a single instance of the namespace.
 In the general case no, see the first reply in 
 https://forum.dlang.org/post/xdaedmlbbqtztiqcwxll forum.dlang.org
The idea is to not have a namespace
That is what we have been arguing for all thread...
 I don't see what making an alias to a namespace has to do with 
 it.
That was your suggested workaround, was it not? If not you have _really_ lost me.
Aug 07 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/7/2018 12:08 AM, Nicholas Wilson wrote:
 I don't see what making an alias to a namespace has to do with it.
That was your suggested workaround, was it not?
No, it was not. It was about making an alias to the members of the namespace.
Aug 07 2018
parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/7/2018 1:13 AM, Walter Bright wrote:
 On 8/7/2018 12:08 AM, Nicholas Wilson wrote:
 I don't see what making an alias to a namespace has to do with it.
That was your suggested workaround, was it not?
No, it was not. It was about making an alias to the members of the namespace.
BTW, the mass confusion and misunderstandings in this thread is why Manu should write a DIP.
Aug 07 2018
prev sibling next sibling parent Daniel N <no public.email> writes:
On Tuesday, 7 August 2018 at 02:25:32 UTC, Walter Bright wrote:
 Let's see if we can find some common ground.

 The boilerplate I suggested seems to enable DPP to generate 
 working code that behaves "as if" the namespace scope is not 
 there, even for nested namespaces.

 Is this correct?
Almost. extern(C++, noise1.noise2.noise3) void fun(); alias fun = noise1.noise2.noise3.fun; void main() { fun(1); } Except the full name bleeds to the user | | V my.d(4): Error: function my.noise1.noise2.noise3.fun() is not callable using argument types (int) Would you prefer to: 1) Keep as is, let it bleed 2) Suppress namespaces when printing error messages 3) Never generate the namespace in the first-place
Aug 07 2018
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Tuesday, 7 August 2018 at 02:25:32 UTC, Walter Bright wrote:
 Let's see if we can find some common ground.

 The boilerplate I suggested seems to enable DPP to generate 
 working code that behaves "as if" the namespace scope is not 
 there, even for nested namespaces.

 Is this correct?
Yes, I've already implemented it. I'm not sure what the impact will be with nested namespaces in real headers. I guess we'll have to see.
Aug 07 2018
parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/7/2018 3:49 AM, Atila Neves wrote:
 Yes, I've already implemented it.
Wonderful!
 I'm not sure what the impact will be with nested namespaces in real headers. I 
 guess we'll have to see.
Yes.
Aug 07 2018
prev sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 30 July 2018 at 03:05:44 UTC, Manu wrote:
 In 20 years, I've never seen 2 namespaces in the same file. And 
 if the C++
 code were like that, I'd break it into separate modules anyway, 
 because
 that's what every D programmer would expect.
It is common in C++ to have multiple hierarchical namespaces in the same file...
Jul 30 2018
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
On Sun, 29 Jul 2018 at 04:04, Jonathan M Davis via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Sunday, July 29, 2018 2:28:08 AM MDT Walter Bright via Digitalmars-d
 wrote:
 On 7/29/2018 1:15 AM, Manu wrote:
 All we're asking for is that C++ namespaces do **nothing** except affect
 the mangling.
If I do that, the next bug report will be: extern (C++, "ab") { void foo(); } extern (C++, "cd") { void foo(); } // Error, foo() is already declared foo(); // which one gets called? The reason namespaces were added to C++ is to not have such name collisions. Namespaces in C++ introduce a scope. D cannot interoperate with this without introducing a scope as well.
I guess that the argument at that point is that you would have to put them in separate D modules, just like you would if they were extern(D) functions.
Or extern(C), or extern(C++), or extern(ObjectiveC)...
Jul 29 2018
prev sibling next sibling parent bachmeier <no spam.net> writes:
On Sunday, 29 July 2018 at 08:28:08 UTC, Walter Bright wrote:
 On 7/29/2018 1:15 AM, Manu wrote:
 All we're asking for is that C++ namespaces do **nothing** 
 except affect the mangling.
If I do that, the next bug report will be: extern (C++, "ab") { void foo(); } extern (C++, "cd") { void foo(); } // Error, foo() is already declared foo(); // which one gets called?
mangle (C++, "ab") { void foo(); } mangle (C++, "cd") { void foo(); } // Error, foo() is already That would not require any changes to extern and there would be no sensible argument for trying to define foo twice.
Jul 29 2018
prev sibling parent reply Seb <seb wilzba.ch> writes:
On Sunday, 29 July 2018 at 08:28:08 UTC, Walter Bright wrote:
 On 7/29/2018 1:15 AM, Manu wrote:
 All we're asking for is that C++ namespaces do **nothing** 
 except affect the mangling.
If I do that, the next bug report will be: extern (C++, "ab") { void foo(); } extern (C++, "cd") { void foo(); } // Error, foo() is already declared foo(); // which one gets called? The reason namespaces were added to C++ is to not have such name collisions. Namespaces in C++ introduce a scope. D cannot interoperate with this without introducing a scope as well.
FYI: this doesn't error as of now, but with https://github.com/dlang/dmd/pull/8429 it will.
Jul 29 2018
parent Walter Bright <newshound2 digitalmars.com> writes:
On 7/29/2018 2:44 PM, Seb wrote:
 FYI: this doesn't error as of now,
Right, but also you cannot specify which will be called.
Jul 29 2018
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 29.07.2018 09:37, Walter Bright wrote:
 On 7/28/2018 11:06 PM, Nicholas Wilson wrote:
 Then again I don't see any (non philosophical/compiler front end 
 internal) issue why you can't reopen a namespace. D is supposed to be 
 pragmatic, after all.
Consider if a template reopens a namespace and throws a few more overloads in it. Then, what's in the namespace is dependent on which expansions are done, in which order.
How would that work? I don't think this is possible.
 Throw in the inevitable circular 
 references. Do people write code like that? Sure as shootin', they do, 
 and they demand that it work, and file lots of bug reports about the 
 erratic behavior.
 ...
Well, they already can do this with the global scope.
 Next, consider a function body throwing a few more overloads in. Now, if 
 the function body is compiled or not (and the compiler tries to avoid 
 compiling bodies unless it has to) affects code that is outside of the 
 function.
 ...
Again, this does not seem possible.
 C++ is full of stuff like that. The difference is, when code fails in 
 some bizarre way, programmers blame themselves and throw money at Scott 
 Meyers to educate them on how to avoid writing such code. For D, they 
 blame me.
 
 The last time we fixed scope lookup to make it more complicated was with 
 imports, and that took YEARS to sort out.
 
 So I'm a little reluctant to add features that will result in a rat's 
 nest of problems I can neither explain nor fix, then someone will add 
 4000 incomprehensible lines to fix 2 cases and add 5 or 6 bizarre 
 regressions in the process and people complain the compiler is unstable. 
 :-)
Well, for Atila, the only issue is that there cannot be two namespace declarations of the same name in the same source file. I don't think it is necessary to change scope lookup rules at all, just put declarations from namespaces with identical names into the same name space. Note that we already need to define semantics for code like this: struct ns{ static: int decl0; static if(is(typeof(reopenNS1))) mixin(reopenNS1); } int arbitrarily_many_intermediate_declarations0; enum reopenNS1=q{ int decl1; static if(is(typeof(reopenNS2))) mixin(reopenNS2); }; int arbitrarily_many_intermediate_declarations1; enum reopenNS2=q{ int decl2; static if(is(typeof(reopenNS3))) mixin(reopenNS3); }; static assert(is(typeof(ns.decl0+ns.decl1+ns.decl2))); In terms of lookup, this is a similar problem to namespaces. I think Atila could probably even emit ugly code like this to solve his original problem, but it would slow down compilation unnecessarily. There are no new lookup issues here.
Jul 30 2018
prev sibling next sibling parent Jim Balter <Jim Balter.name> writes:
On Sunday, 29 July 2018 at 03:20:29 UTC, Walter Bright wrote:
 On 7/28/2018 11:18 AM, Manu wrote:
 Make a PR that implements namespace as a string... I will use 
 that fork of D forever.
1. Look how it is mangled on the C++ side. (Use "grep" on the object file.) 2. Use: pragma(mangle, "the mangled name")
People are trying to read C++ header files and convert the declarations ... how is that supposed to work? Even if they were manually adding declarations, this doesn't sound like a feasible approach.
Jul 29 2018
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Sunday, 29 July 2018 at 03:20:29 UTC, Walter Bright wrote:
 On 7/28/2018 11:18 AM, Manu wrote:
 Make a PR that implements namespace as a string... I will use 
 that fork of D forever.
1. Look how it is mangled on the C++ side. (Use "grep" on the object file.) 2. Use: pragma(mangle, "the mangled name")
This doesn't work for templates. If it did I wouldn't have an issue since libclang tells me what the mangling is.
Jul 30 2018
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 7/30/2018 6:48 AM, Atila Neves wrote:
 This doesn't work for templates. If it did I wouldn't have an issue since 
 libclang tells me what the mangling is.
You're right.
Jul 30 2018
prev sibling parent reply Daniel N <no public.email> writes:
On Monday, 30 July 2018 at 13:48:46 UTC, Atila Neves wrote:
 On Sunday, 29 July 2018 at 03:20:29 UTC, Walter Bright wrote:
 On 7/28/2018 11:18 AM, Manu wrote:
 Make a PR that implements namespace as a string... I will use 
 that fork of D forever.
1. Look how it is mangled on the C++ side. (Use "grep" on the object file.) 2. Use: pragma(mangle, "the mangled name")
This doesn't work for templates. If it did I wouldn't have an issue since libclang tells me what the mangling is.
What is the deal-breaker with templates? For simple functions libclang + pragma seems the best option right now. template fun() { pragma(mangle, "_ZN2ns3funEv") extern(C++) void fun() {} } mixin fun;
Jul 31 2018
next sibling parent Mathias Lang <pro.mathias.lang gmail.com> writes:
On Tuesday, 31 July 2018 at 08:33:52 UTC, Daniel N wrote:
 On Monday, 30 July 2018 at 13:48:46 UTC, Atila Neves wrote:
 On Sunday, 29 July 2018 at 03:20:29 UTC, Walter Bright wrote:
 On 7/28/2018 11:18 AM, Manu wrote:
 Make a PR that implements namespace as a string... I will 
 use that fork of D forever.
1. Look how it is mangled on the C++ side. (Use "grep" on the object file.) 2. Use: pragma(mangle, "the mangled name")
This doesn't work for templates. If it did I wouldn't have an issue since libclang tells me what the mangling is.
What is the deal-breaker with templates? For simple functions libclang + pragma seems the best option right now. template fun() { pragma(mangle, "_ZN2ns3funEv") extern(C++) void fun() {} } mixin fun;
Your template doesn't have any template parameter. Bear in mind mangling is dependent on the instance, not the declaration. Once you add some template parameter, you need to mangle your template parameter list, which you could *almost* reasonably do with CTFE, but since you are on POSIX, you also got fun things like components and template parameter substitution. Example: ``` struct Array16479 (Arg) { Arg* data; } Array16479!(FuncT2) func16479_4 (FuncT1, FuncT2) (FuncT1); static assert(func16479_4!(int, float).mangleof == `_Z11func16479_4IifE10Array16479IT0_ET_`); ``` As you see the return value (`Array16479IT0_E`) encode a backreference to the symbol's template parameter: T0_ reference the second template argument. If you throw some more language features (e.g. aliases) you quickly realize you need a full semantic analysis to get the mangling right on templates. More test cases/examples (and shameless self plug): https://github.com/dlang/dmd/pull/8455/files
Jul 31 2018
prev sibling parent Atila Neves <atila.neves gmail.com> writes:
On Tuesday, 31 July 2018 at 08:33:52 UTC, Daniel N wrote:
 On Monday, 30 July 2018 at 13:48:46 UTC, Atila Neves wrote:
 On Sunday, 29 July 2018 at 03:20:29 UTC, Walter Bright wrote:
 On 7/28/2018 11:18 AM, Manu wrote:
 Make a PR that implements namespace as a string... I will 
 use that fork of D forever.
1. Look how it is mangled on the C++ side. (Use "grep" on the object file.) 2. Use: pragma(mangle, "the mangled name")
This doesn't work for templates. If it did I wouldn't have an issue since libclang tells me what the mangling is.
What is the deal-breaker with templates? For simple functions libclang + pragma seems the best option right now. template fun() { pragma(mangle, "_ZN2ns3funEv") extern(C++) void fun() {} } mixin fun;
extern(C++) { void foo(T)() { } } It doesn't have a mangling until it has an instantiation. Even if it were possible to know which exact instantitations the code that imports this uses, there's no way I can declare the mangling scheme to the D compiler.
Jul 31 2018