Thread overview
Should an 'extern(C++, "ns"):' override previous ones in the same scope?
Sep 07, 2019
Max Samukha
Sep 07, 2019
Jonathan M Davis
Sep 07, 2019
Exil
Sep 07, 2019
Exil
Sep 07, 2019
Jonathan M Davis
Sep 08, 2019
Max Samukha
Sep 08, 2019
Jonathan M Davis
Sep 08, 2019
Max Samukha
Sep 08, 2019
Exil
Sep 08, 2019
Jonathan M Davis
September 07, 2019
extern(C++, "ns1"):
extern(C++, "ns2"): // Not in nested scope. Should it supersede?
void foo();

pragma(msg, foo.mangleof); // _ZN3ns13ns23fooEv instead of expected _ZN3ns23fooEv

Is that by design?
September 07, 2019
On Saturday, September 7, 2019 9:15:44 AM MDT Max Samukha via Digitalmars-d- learn wrote:
> extern(C++, "ns1"):
> extern(C++, "ns2"): // Not in nested scope. Should it supersede?
> void foo();
>
> pragma(msg, foo.mangleof); // _ZN3ns13ns23fooEv instead of
> expected _ZN3ns23fooEv
>
> Is that by design?

If you have

@safe:
@system:

then @system overrides @safe. And you can't have a C++ symbol that lives in multiple namespaces. So, I would consider it a bug if your example doesn't put foo in the namespace ns2, overriding ns1. IMHO, overriding is the only behavior that makes sense, and anything else would be inconsistent with how other, incompatible attributes are applied. Certainly, treating

extern(C++, "ns1"):
extern(C++, "ns2"):

as equivalent to

extern(C++, "ns1::ns2"):

makes no sense whatsoever IMHO. IIRC, this version of extern(C++) didn't go through the DIP process and was simply added via a PR. So, it wouldn't surprise me if the person who implemented it didn't even think about the

extern(C++, "ns1"):
extern(C++, "ns2"):

case and didn't test for it properly.

- Jonathan M Davis



September 07, 2019
On Saturday, 7 September 2019 at 17:22:07 UTC, Jonathan M Davis wrote:
> makes no sense whatsoever IMHO. IIRC, this version of extern(C++) didn't go through the DIP process and was simply added via a PR.


The original extern(C++) worked the same way. Since it was implemented in v2.066.0 by the looks of it. IIRC the only thing the PR did was basically remove the code that added new objects. So it's to be expected they behave the same way.

https://run.dlang.io/is/v1vFeZ

    extern(C++, ns1):
    extern(C++, ns2):
    void foo();

    pragma(msg, foo.mangleof);

    void main() { }

Since      2.066.0: Success with output: _ZN3ns13ns23fooEv
September 07, 2019
On Saturday, 7 September 2019 at 17:22:07 UTC, Jonathan M Davis wrote:
>
> @safe:
> @system:
>
> then @system overrides @safe.

Just to add onto this, you can't do:

    @safe @system void foo(); // error


but you can do:

    extern(C++, ns1) extern(C++, ns2) void foo(); // ok


September 07, 2019
On Saturday, September 7, 2019 3:40:58 PM MDT Exil via Digitalmars-d-learn wrote:
> On Saturday, 7 September 2019 at 17:22:07 UTC, Jonathan M Davis
>
> wrote:
> > @safe:
> > @system:
> >
> > then @system overrides @safe.
>
> Just to add onto this, you can't do:
>
>      @safe @system void foo(); // error
>
>
> but you can do:
>
>      extern(C++, ns1) extern(C++, ns2) void foo(); // ok

It makes no sense to apply multiple namespaces to the same symbol. I expect that this behavior is due to a lack of testing (the same with the out of order weirdness in the other post). It's the sort of thing that you test when you're trying to make sure that the feature does the right thing when people use it incorrectly, not the sort of thing when you're trying to make sure that the feature works as intended, so it's easy to forget.

My guess is that this behavior leaked its way in due to the fact that you
need to be able to put multiple extern(C++) declarations on a symbol when
you use extern(C++, struct) or extern(C++, class) in addition to the
extern(C++) for the namespace.

- Jonathan M Davis



September 08, 2019
On Saturday, 7 September 2019 at 22:19:48 UTC, Jonathan M Davis wrote:
> On Saturday, September 7, 2019 3:40:58 PM MDT Exil via Digitalmars-d-learn wrote:
>> On Saturday, 7 September 2019 at 17:22:07 UTC, Jonathan M Davis
>>
>> wrote:
>> > @safe:
>> > @system:
>> >
>> > then @system overrides @safe.
>>
>> Just to add onto this, you can't do:
>>
>>      @safe @system void foo(); // error
>>
>>
>> but you can do:
>>
>>      extern(C++, ns1) extern(C++, ns2) void foo(); // ok
>
> It makes no sense to apply multiple namespaces to the same symbol. I expect that this behavior is due to a lack of testing (the same with the out of order weirdness in the other post). It's the sort of thing that you test when you're trying to make sure that the feature does the right thing when people use it incorrectly, not the sort of thing when you're trying to make sure that the feature works as intended, so it's easy to forget.
>
> My guess is that this behavior leaked its way in due to the fact that you
> need to be able to put multiple extern(C++) declarations on a symbol when
> you use extern(C++, struct) or extern(C++, class) in addition to the
> extern(C++) for the namespace.
>
> - Jonathan M Davis

I wonder how that undocumented and not well thought-through (or having some unobvious justifications) feature made it into a stable release.

Anyway, thank you for your help. I will probably file a bug report when I have time.





September 08, 2019
On Sunday, September 8, 2019 3:03:31 AM MDT Max Samukha via Digitalmars-d- learn wrote:
> On Saturday, 7 September 2019 at 22:19:48 UTC, Jonathan M Davis
>
> wrote:
> > On Saturday, September 7, 2019 3:40:58 PM MDT Exil via
> >
> > Digitalmars-d-learn wrote:
> >> On Saturday, 7 September 2019 at 17:22:07 UTC, Jonathan M Davis
> >>
> >> wrote:
> >> > @safe:
> >> > @system:
> >> >
> >> > then @system overrides @safe.
> >>
> >> Just to add onto this, you can't do:
> >>      @safe @system void foo(); // error
> >>
> >> but you can do:
> >>      extern(C++, ns1) extern(C++, ns2) void foo(); // ok
> >
> > It makes no sense to apply multiple namespaces to the same symbol. I expect that this behavior is due to a lack of testing (the same with the out of order weirdness in the other post). It's the sort of thing that you test when you're trying to make sure that the feature does the right thing when people use it incorrectly, not the sort of thing when you're trying to make sure that the feature works as intended, so it's easy to forget.
> >
> > My guess is that this behavior leaked its way in due to the
> > fact that you
> > need to be able to put multiple extern(C++) declarations on a
> > symbol when
> > you use extern(C++, struct) or extern(C++, class) in addition
> > to the
> > extern(C++) for the namespace.
> >
> > - Jonathan M Davis
>
> I wonder how that undocumented and not well thought-through (or having some unobvious justifications) feature made it into a stable release.
>
> Anyway, thank you for your help. I will probably file a bug report when I have time.

The C++ support has been improved kind of piecemeal over time, and initially, none of it was documented. So, it wasn't exactly fully planned out when it was added. IIRC, it was added originally so that the dmd frontend could be moved to D. The DIP process was very different at that point, and it was much more common then for Walter or one of the other core developers to just propose a feature in a PR and get it merged. I expect that the oddities in the implementation stem from stuff that whoever implemented it didn't think to try. The whole process is much more rigorous now than it used to be.

- Jonathan M Davis



September 08, 2019
On Sunday, 8 September 2019 at 09:35:03 UTC, Jonathan M Davis wrote:

> The C++ support has been improved kind of piecemeal over time, and initially, none of it was documented. So, it wasn't exactly fully planned out when it was added. IIRC, it was added originally so that the dmd frontend could be moved to D. The DIP process was very different at that point, and it was much more common then for Walter or one of the other core developers to just propose a feature in a PR and get it merged. I expect that the oddities in the implementation stem from stuff that whoever implemented it didn't think to try. The whole process is much more rigorous now than it used to be.
>
> - Jonathan M Davis

Good to know, thank you.
September 08, 2019
On Saturday, 7 September 2019 at 22:19:48 UTC, Jonathan M Davis wrote:
> On Saturday, September 7, 2019 3:40:58 PM MDT Exil via Digitalmars-d-learn wrote:
>> On Saturday, 7 September 2019 at 17:22:07 UTC, Jonathan M Davis
>>
>> wrote:
>> > @safe:
>> > @system:
>> >
>> > then @system overrides @safe.
>>
>> Just to add onto this, you can't do:
>>
>>      @safe @system void foo(); // error
>>
>>
>> but you can do:
>>
>>      extern(C++, ns1) extern(C++, ns2) void foo(); // ok
>
> It makes no sense to apply multiple namespaces to the same symbol. I expect that this behavior is due to a lack of testing (the same with the out of order weirdness in the other post). It's the sort of thing that you test when you're trying to make sure that the feature does the right thing when people use it incorrectly, not the sort of thing when you're trying to make sure that the feature works as intended, so it's easy to forget.
>
> My guess is that this behavior leaked its way in due to the fact that you
> need to be able to put multiple extern(C++) declarations on a symbol when
> you use extern(C++, struct) or extern(C++, class) in addition to the
> extern(C++) for the namespace.
>
> - Jonathan M Davis

You don't need to make guesses or assumptions. It most definitely was intentional.

https://github.com/dlang/dmd/commit/4b2578e208f2af9a02159fc2d8d87fb17b09005e#diff-62dcb5f0ffc3089b7565897d8beb3322R617


By the looks of it, this feature was also implemented before extern(C++, struct/class).

September 08, 2019
On Sunday, September 8, 2019 12:12:53 PM MDT Exil via Digitalmars-d-learn wrote:
> On Saturday, 7 September 2019 at 22:19:48 UTC, Jonathan M Davis
>
> wrote:
> > On Saturday, September 7, 2019 3:40:58 PM MDT Exil via
> >
> > Digitalmars-d-learn wrote:
> >> On Saturday, 7 September 2019 at 17:22:07 UTC, Jonathan M Davis
> >>
> >> wrote:
> >> > @safe:
> >> > @system:
> >> >
> >> > then @system overrides @safe.
> >>
> >> Just to add onto this, you can't do:
> >>      @safe @system void foo(); // error
> >>
> >> but you can do:
> >>      extern(C++, ns1) extern(C++, ns2) void foo(); // ok
> >
> > It makes no sense to apply multiple namespaces to the same symbol. I expect that this behavior is due to a lack of testing (the same with the out of order weirdness in the other post). It's the sort of thing that you test when you're trying to make sure that the feature does the right thing when people use it incorrectly, not the sort of thing when you're trying to make sure that the feature works as intended, so it's easy to forget.
> >
> > My guess is that this behavior leaked its way in due to the
> > fact that you
> > need to be able to put multiple extern(C++) declarations on a
> > symbol when
> > you use extern(C++, struct) or extern(C++, class) in addition
> > to the
> > extern(C++) for the namespace.
> >
> > - Jonathan M Davis
>
> You don't need to make guesses or assumptions. It most definitely was intentional.
>
> https://github.com/dlang/dmd/commit/4b2578e208f2af9a02159fc2d8d87fb17b0900 5e#diff-62dcb5f0ffc3089b7565897d8beb3322R617
>
>
> By the looks of it, this feature was also implemented before
> extern(C++, struct/class).

Well, it's inconsistent with the rest of the language and bad design IMHO. And even if it were desirable behavior, it clearly becomes a mess with the ordering once the attributes are no longer directly on the symbol. Of course, ideally, the whole extern(C++) feature with identifiers instead of strings for the namespace would be deprecated anyway.

- Jonathan M Davis