July 30, 2018
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

July 30, 2018
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.


July 30, 2018
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.
July 30, 2018
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.
July 30, 2018
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.

July 30, 2018
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.
July 30, 2018
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.
July 30, 2018
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
July 30, 2018
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.
July 30, 2018
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.