August 02, 2018
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?
August 02, 2018
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.

August 03, 2018
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?
August 03, 2018
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
August 03, 2018
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. :)

August 03, 2018
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).
August 03, 2018
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
August 03, 2018
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.)
August 03, 2018
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.
August 03, 2018
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