digitalmars.D - Is there any good reason why C++ namespaces are "closed" in D?
- Atila Neves (37/37) Jul 27 2018 I understand that being able to "reopen" namespaces in C++ is
- kinke (3/3) Jul 27 2018 This limitation really seems to make no sense, especially since
- Timon Gehr (6/15) Jul 27 2018 Both of the extern(C++, ns) declarations create a separate namespace
- Walter Bright (26/32) Jul 27 2018 Namespaces have semantic implications, too, such as overload resolutions...
- Laeeth Isharc (15/52) Jul 27 2018 Thanks for the explanation, Walter.
- Walter Bright (4/5) Jul 27 2018 One way is for the C++ => D translator to gather all the members of a na...
- Atila Neves (4/10) Jul 30 2018 As mentioned in the original post, the gathering is going to be
- Walter Bright (4/7) Jul 30 2018 I thought you were running the preprocessor first?
- Laeeth Isharc (4/10) Jul 31 2018 So a new post preprocessor stage that parses the produced D code
- Walter Bright (6/17) Aug 01 2018 I don't know how Atila's translator works.
- Manu (5/22) Aug 01 2018 None of this nuisance for Atila is necessary. You're just making
- Ali (5/7) Aug 03 2018 Just wanted to +1000000 on this one
- Manu (12/16) Jul 28 2018 Correct. And D has modules. Solved.
- Atila Neves (8/39) Jul 30 2018 Structs aren't namespaces, I wouldn't expect them to behave the
- Walter Bright (17/32) Jul 30 2018 They do in C++. That was the whole point of adding namespaces:
- Atila Neves (13/41) Jul 31 2018 I meant "should they in D, though?". I don't want to import C++
- Walter Bright (6/9) Aug 01 2018 Calling them std.string will already cause problems, because there's an
- Manu (8/45) Jul 28 2018 +1
- Walter Bright (4/6) Jul 28 2018 1. Look how it is mangled on the C++ side. (Use "grep" on the object fil...
- Manu (4/11) Jul 28 2018 Don't troll me on this one, this is a very sensitive topic!
- Walter Bright (18/20) Jul 29 2018 Here's another method:
- Walter Bright (2/2) Jul 29 2018 The name can be "transferred" into the global namespace using an alias.
- Atila Neves (21/41) Jul 30 2018 void main() {
- Walter Bright (6/30) Jul 30 2018 You'll need to add:
- Walter Bright (17/18) Jul 30 2018 Check this:
- Nicholas Wilson (11/18) Jul 28 2018 That a) doesn't scale in a real dynamic codebase (think
- Walter Bright (18/20) Jul 29 2018 Consider if a template reopens a namespace and throws a few more overloa...
- Manu (23/54) Jul 29 2018 I don't understand your claims that it would somehow become problematic ...
- Walter Bright (8/10) Jul 29 2018 If I do that, the next bug report will be:
- Jonathan M Davis (15/25) Jul 29 2018 I guess that the argument at that point is that you would have to put th...
- kinke (24/27) Jul 29 2018 Yep, that'd sound acceptable to me, implying that
- Jonathan M Davis (12/39) Jul 29 2018 Honestly, I'd expecting folks doing bindings for anything serious would ...
- Manu (5/16) Jul 29 2018 It's beautiful!
- Walter Bright (2/23) Jul 29 2018 But that works now, I suggested it, and you didn't find it acceptable !!...
- Nicholas Wilson (10/38) Jul 29 2018 With the above extern(C++, "cppns") (note the quotes) defines the
- Walter Bright (5/6) Jul 29 2018 I meant that you can today "reopen" namespace scopes by placing them in ...
- Manu (8/12) Jul 29 2018 That's not the same thing... you can create a _different one_ with the
- Walter Bright (7/22) Jul 30 2018 No, they do not conflict. They are qualified by the module name, for exa...
- Walter Bright (20/37) Jul 29 2018 You must have missed my other post:
- ezneh (9/20) Jul 29 2018 Wouldn't something like this would prevent that :
- Manu (11/21) Jul 29 2018 You're really reaching here. Of course, this error is legitimate and cor...
- Walter Bright (5/7) Jul 29 2018 But then you cannot interface with this C++ code:
- Nicholas Wilson (4/13) Jul 29 2018 But you can if ab and cd are in different modules. The point is
- Nicholas Wilson (2/18) Jul 29 2018 Not that this alleviates Alita's issues at all.
- Manu (39/48) Jul 29 2018 ab.d
- Walter Bright (14/30) Jul 30 2018 extern(C++, ab) void foo();
- Daniel N (10/15) Jul 30 2018 I tried that but it mangles wrong.. it includes "S1" which is not
- CommanderZot (3/24) Jul 30 2018 there also is an issue when using extern(C) in mixins. see
- Walter Bright (2/3) Jul 30 2018 You're right, and I fixed that in a reply to Atila.
- Manu (24/52) Jul 30 2018 Sure it 'works', but it's an annoying point of friction, and it
- Steven Schveighoffer (16/82) Jul 30 2018 hehe, you need to put them all into one extern(C++, std), right? Not to
- Walter Bright (7/15) Jul 30 2018 You can reduce it to:
- Manu (20/35) Jul 30 2018 We're talking about multiple C++ files, not one.
- Walter Bright (3/6) Jul 30 2018 I have literally no idea what you mean. That's why I suggest you show wh...
- Walter Bright (16/16) Jul 30 2018 My issue is you're presenting solutions. But I have no idea what the pro...
- Manu (109/124) Jul 31 2018 I'm not asking for workarounds or 'solutions'. I know the workarounds
- Jacob Carlborg (6/20) Jul 31 2018 This works:
- Manu (9/27) Jul 31 2018 Right... But did you miss the point? The D module does the organisation ...
- Rubn (9/49) Jul 31 2018 Can you give some examples of those certain situations? It would
- Nicholas Wilson (2/8) Jul 31 2018 Indeed, case in point: std
- Walter Bright (36/78) Aug 01 2018 You can write it like this:
- Jonathan M Davis (26/54) Aug 01 2018 Not to say that that can't work, but I have to say that it seems pretty ...
- Walter Bright (46/51) Aug 01 2018 What is normal is a slippery concept, especially when one is comparing d...
- Rubn (6/17) Aug 01 2018 You can do that today, just remove the "extern(C++, ...)" part
- Walter Bright (9/26) Aug 01 2018 The difference is those names are supposedly in different namespaces, gi...
- Johannes Pfau (8/58) Aug 01 2018 Why would that not work with a translation tool? Just establish a fixed ...
- Johannes Pfau (19/36) Aug 01 2018 You probably didn't completely think this through: Earlier you suggested...
- rjframe (9/17) Aug 02 2018 Disclaimer: no knowledge or experience to back up my assumptions:
- Steven Schveighoffer (15/61) Aug 02 2018 I challenge you to find any C++ code that has two identical function
- Manu (85/136) Aug 04 2018 I'm sorry, that doesn't come remotely close justifying the imbalance.
- Walter Bright (16/17) Aug 05 2018 I get it, Manu, you don't find my arguments compelling. You've put these...
- Manu (11/16) Aug 05 2018 So, what you're saying is "I hear you, and I will never change it
- 12345swordy (5/7) Aug 06 2018 I think you and Walter Bright made good points and I think a
- Walter Bright (10/11) Aug 06 2018 Producing a DIP is a good idea, it provides an anchor point for any futu...
- Danni Coy (8/27) Aug 06 2018 Outside perspective here and possibly stupid question. Is there any way ...
- bachmeier (7/14) Aug 06 2018 I haven't read all of the posts in this thread, but my
- tide (17/37) Aug 06 2018 What's your crossplatform workaround if I have a namespace named
- Walter Bright (6/12) Aug 06 2018 See my reply to Rick Cattermole.
- tide (12/21) Aug 06 2018 But that's not currently implemented is it? Your proposed
- Walter Bright (4/5) Aug 06 2018 1. I'm only here to help, and am not interested in scoring debate points...
- Manu (3/59) Aug 01 2018 Thank you Jonathan.
- Manu (31/37) Aug 01 2018 I'm not quite sure this is a fair connection... or certainly that's
- Walter Bright (5/7) Aug 01 2018 Don't confuse you not agreeing with it with I never justified it.
- Johannes Pfau (11/21) Aug 01 2018 In your most recent posts you provided some rationale for this, but
- Manu (21/28) Aug 01 2018 We have demonstrated consistent ongoing issues and frustration for 6
- Walter Bright (25/29) Aug 02 2018 Which keywords were those?
- rikki cattermole (4/27) Aug 02 2018 8. if any identifier starts with a keyword and ends with at minimum one
- Walter Bright (3/5) Aug 02 2018 This will break existing code. A double underscore prefix is reserved fo...
- rikki cattermole (3/10) Aug 02 2018 Because it will affect mangling only, do we have any examples of c/c++
- Walter Bright (2/4) Aug 05 2018 The __ scheme won't break existing code, and we don't need a survey to s...
- Walter Bright (2/4) Aug 02 2018 Have you ever tried the alias method I proposed?
- Manu (5/9) Aug 02 2018 Of course, it's the only tool we have here, and a major source of my
- Walter Bright (2/5) Aug 02 2018 Why is it frustrating?
- Mathias Lang (11/15) Jul 31 2018 And only experience can tell if those ideas turn out to be bad,
- Atila Neves (10/22) Jul 31 2018 Because one C++ file != one C++ translation unit. All of them
- Walter Bright (16/19) Aug 01 2018 Why doesn't it count? The user doesn't need to write that code, the tran...
- Johannes Pfau (13/21) Aug 01 2018 I remember a time when people here were joking about all the boilerplate...
- Walter Bright (2/4) Aug 02 2018 Please read my postings in this thread, then.
- Daniel N (26/32) Aug 02 2018 I know you have been very patient with explaining this, but I've
- Steven Schveighoffer (15/54) Aug 02 2018 The example that Walter keeps bringing up is one where the C++ code has
- rikki cattermole (5/22) Aug 02 2018 That's easy to solve.
- Daniel N (4/14) Aug 02 2018 I see, thanks.
- Walter Bright (40/50) Aug 03 2018 You'd be amazed at what people do and then set their entire store based ...
- Rubn (53/131) Aug 03 2018 A simple regex could have fixed that problem. They dug themselves
- Laeeth Isharc (23/45) Aug 03 2018 Why would you write bindings if the computer can do it for you,
- Manu (43/52) Aug 04 2018 Faster and consistently, sure. But I don't think 'better' is possible.
- Laeeth Isharc (21/101) Aug 04 2018 Would it be inaccurate to make a distinction between bindings and
- Atila Neves (9/15) Aug 06 2018 Bindings != wrappers. I agree that wrappers will nearly always
- tide (27/76) Aug 04 2018 With the current tools the ones that generate D files to be used
- Jonathan M Davis (37/41) Aug 04 2018 In general, it's easier for maintenance if there's a 1:1 correlation bet...
- tid3 (15/70) Aug 04 2018 Alright that's fair but it still isn't ever going to be 1:1. I've
- Atila Neves (8/26) Aug 06 2018 If the D files are to be checked in, then yes, that'd be a
- Steven Schveighoffer (38/54) Aug 04 2018 And that's OK with me. I'm OK with D saying it only supports reasonably
- tide (8/12) Aug 04 2018 On another note, why aren't const pointers to mutable data
- aliak (13/18) Aug 06 2018 This would still be true if current behavior was kept and
- Atila Neves (49/64) Aug 03 2018 Good point.
- Daniel N (5/10) Aug 03 2018 The user will actually see it, because the full name will be in
- CommanderZot (4/9) Aug 03 2018 We can also just keep the current behaviour and implement
- Walter Bright (41/58) Aug 03 2018 Try this:
- Atila Neves (29/90) Aug 06 2018 That doesn't solve the problem at all. I was toying with being
- Walter Bright (4/4) Aug 06 2018 Let's see if we can find some common ground.
- Nicholas Wilson (4/9) Aug 06 2018 Yes, but only for a single instance of the namespace.
- Walter Bright (3/6) Aug 06 2018 The idea is to not have a namespace, I don't see what making an alias to...
- Nicholas Wilson (4/11) Aug 07 2018 That was your suggested workaround, was it not? If not you have
- Walter Bright (2/4) Aug 07 2018 No, it was not. It was about making an alias to the members of the names...
- Walter Bright (3/7) Aug 07 2018 BTW, the mass confusion and misunderstandings in this thread is why Manu...
- Daniel N (16/21) Aug 07 2018 Almost.
- Atila Neves (4/9) Aug 07 2018 Yes, I've already implemented it.
- Walter Bright (3/6) Aug 07 2018 Yes.
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (3/8) Jul 30 2018 It is common in C++ to have multiple hierarchical namespaces in
- Manu (3/21) Jul 29 2018 Or extern(C), or extern(C++), or extern(ObjectiveC)...
- bachmeier (5/13) Jul 29 2018 mangle (C++, "ab") { void foo(); }
- Seb (3/14) Jul 29 2018 FYI: this doesn't error as of now, but with
- Walter Bright (2/3) Jul 29 2018 Right, but also you cannot specify which will be called.
- Timon Gehr (29/60) Jul 30 2018 Well, they already can do this with the global scope.
- Jim Balter (5/12) Jul 29 2018 People are trying to read C++ header files and convert the
- Atila Neves (3/10) Jul 30 2018 This doesn't work for templates. If it did I wouldn't have an
- Walter Bright (2/4) Jul 30 2018 You're right.
- Daniel N (10/23) Jul 31 2018 What is the deal-breaker with templates? For simple functions
- Mathias Lang (22/46) Jul 31 2018 Your template doesn't have any template parameter. Bear in mind
- Atila Neves (9/33) Jul 31 2018 extern(C++) {
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
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
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
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
On Friday, 27 July 2018 at 22:50:20 UTC, Walter Bright wrote:On 7/27/2018 10:28 AM, Atila Neves wrote: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).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 doingthat 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
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
On Saturday, 28 July 2018 at 01:03:10 UTC, Walter Bright wrote:On 7/27/2018 4:15 PM, Laeeth Isharc wrote:As mentioned in the original post, the gathering is going to be incredibly annoying and I suspect I'll run into problems with macros.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 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 annoyingIf 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
On Saturday, 28 July 2018 at 01:03:10 UTC, Walter Bright wrote:On 7/27/2018 4:15 PM, Laeeth Isharc wrote: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?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 31 2018
On 7/31/2018 3:34 PM, Laeeth Isharc wrote:On Saturday, 28 July 2018 at 01:03:10 UTC, Walter Bright wrote: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.On 7/27/2018 4:15 PM, Laeeth Isharc wrote: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?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.
Aug 01 2018
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: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.On Saturday, 28 July 2018 at 01:03:10 UTC, Walter Bright wrote: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.On 7/27/2018 4:15 PM, Laeeth Isharc wrote: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?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.
Aug 01 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
Aug 03 2018
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
On Friday, 27 July 2018 at 22:50:20 UTC, Walter Bright wrote:On 7/27/2018 10:28 AM, Atila Neves wrote:Should they, though?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.Structs aren't namespaces, I wouldn't expect them to behave the same.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 :-)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.I'm arguing that reopening should be allowed.Such a program can easily do that to `extern(C)`, but doingthat to `extern(C++)` is for some reason not allowed. It is allowed. Just not reopening the same namespace.
Jul 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:They do in C++. That was the whole point of adding namespaces: C: void ns_foo(); C++: namespace ns { void foo(); }On 7/27/2018 10:28 AM, Atila Neves wrote:Should they, though?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.Structs aren't namespaces, I wouldn't expect them to behave the same.From a language perspective, they are namespaces.C++ has a lot of bizarre name lookup behavior.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.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
On Monday, 30 July 2018 at 19:51:09 UTC, Walter Bright wrote:On 7/30/2018 6:45 AM, Atila Neves wrote: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.On Friday, 27 July 2018 at 22:50:20 UTC, Walter Bright wrote:They do in C++. That was the whole point of adding namespaces: C: void ns_foo(); C++: namespace ns { void foo(); }On 7/27/2018 10:28 AM, Atila Neves wrote:Should they, though?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.Technically, yes. But not C++ namespaces.Structs aren't namespaces, I wouldn't expect them to behave the same.From a language perspective, they are namespaces.C++ has a lot of bizarre name lookup behavior.It does. I don't think anyone is suggesting we copy it.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 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.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.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.)
Jul 31 2018
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
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
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
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:Don't troll me on this one, this is a very sensitive topic! I could have a legit mental breakdown ;)Make a PR that implements namespace as a string... I will use that forkof Dforever.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
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
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
On Sunday, 29 July 2018 at 07:45:35 UTC, Walter Bright wrote:On 7/28/2018 9:23 PM, Manu wrote: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.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(); } 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
On 7/30/2018 7:20 AM, Atila Neves wrote:You'll need to add: alias bar = x.bar; which will add bar to the current scope.------ 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.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
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
On Sunday, 29 July 2018 at 03:20:29 UTC, Walter Bright wrote:On 7/28/2018 11:18 AM, Manu wrote: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.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
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
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: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!Then again I don't see any (non philosophical/compiler front endinternal) issuewhy you can't reopen a namespace. D is supposed to be pragmatic, afterall. 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
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
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: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 DavisAll 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
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
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: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 DavisI 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
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
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:But that works now, I suggested it, and you didn't find it acceptable !!?!![...] 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
On Monday, 30 July 2018 at 02:09:37 UTC, Walter Bright wrote:On 7/29/2018 1:52 PM, Manu wrote:No it doesn't. You missedOn Sun, 29 Jul 2018 at 05:10, kinke via Digitalmars-d <digitalmars-d puremagic.com> wrote:But that works now, I suggested it, and you didn't find it acceptable !!?!![...] 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)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.(but I added the quotes in there for you; without quotes is existing defined behaviour which introduces scopes)
Jul 29 2018
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
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: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.No it doesn't.I meant that you can today "reopen" namespace scopes by placing them in separate modules.
Jul 29 2018
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:That's right, I've said that before, and that's why I put "reopen" in quotes.On 7/29/2018 7:50 PM, Nicholas Wilson wrote:That's not the same thing... you can create a _different one_ with the same name in a different module.No it doesn't.I meant that you can today "reopen" namespace scopes by placing them in separate modules.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
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: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; } } } ----[...] 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!
Jul 29 2018
On Sunday, 29 July 2018 at 08:28:08 UTC, Walter Bright wrote:On 7/29/2018 1:15 AM, Manu wrote: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.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
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: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.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
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
On Monday, 30 July 2018 at 02:15:57 UTC, Walter Bright wrote:On 7/29/2018 1:45 PM, Manu wrote: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")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
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:Not that this alleviates Alita's issues at all.On 7/29/2018 1:45 PM, Manu wrote: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")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
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: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.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?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
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
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
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:there also is an issue when using extern(C) in mixins. see https://issues.dlang.org/show_bug.cgi?id=12575struct 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
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
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: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.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.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
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:What is this? I don't get what you are doing here.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!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.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.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.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.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
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();"));Yes, please explain why you can't coalesce the namespace declarations in one C++ file into one namespace declaration.You haven't explained why you can't just move the namespace ns declarations in one file together.Are you serious?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
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: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.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();"));Yes, please explain why you can't coalesce the namespace declarations in one C++ file into one namespace declaration.You haven't explained why you can't just move the namespace ns declarations in one file together.Are you serious?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.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
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
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
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 evenMy 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
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 hereThis works: a.foo(); You don't need "ns" in between the module name and the function. -- /Jacob Carlborg
Jul 31 2018
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: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)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 hereThis works: a.foo(); You don't need "ns" in between the module name and the function.
Jul 31 2018
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: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.On 2018-07-31 10:12, Manu wrote: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)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 hereThis works: a.foo(); You don't need "ns" in between the module name and the function.
Jul 31 2018
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
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 hereYou 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 evenI 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
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: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 DavisGiven 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 hereYou 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()
Aug 01 2018
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
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
On 8/1/2018 7:09 PM, Rubn wrote:On Wednesday, 1 August 2018 at 23:04:01 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. If you *want* them in the same scope in D, you can do that with alias.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
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
On Thursday, 2 August 2018 at 04:59:52 UTC, Walter Bright wrote:On 8/1/2018 7:09 PM, Rubn wrote: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.On Wednesday, 1 August 2018 at 23:04:01 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. If you *want* them in the same scope in D, you can do that with alias.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 02 2018
Am Wed, 01 Aug 2018 16:04:01 -0700 schrieb Walter Bright: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.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.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
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
On Wed, 01 Aug 2018 16:04:01 -0700, Walter Bright wrote:On 8/1/2018 10:24 AM, Jonathan M Davis wrote: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.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).
Aug 02 2018
On 8/1/18 7:04 PM, Walter Bright wrote:On 8/1/2018 10:24 AM, Jonathan M Davis wrote: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. -SteveNot 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.
Aug 02 2018
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: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.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 04 2018
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
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: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?[...]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.
Aug 05 2018
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
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
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:forth[...]I get it, Manu, you don't find my arguments compelling. You've put thesebefore, and I could repeat myself rebutting each. I expect we're at adead endwith 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
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
On Sunday, 5 August 2018 at 23:28:06 UTC, Walter Bright wrote:On 8/4/2018 12:45 AM, Manu wrote: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 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.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
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#N317507You 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
On Monday, 6 August 2018 at 20:35:37 UTC, Walter Bright wrote:On 8/6/2018 11:26 AM, tide wrote: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.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#N317507That'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.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.
Aug 06 2018
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
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:Thank you Jonathan.On 7/31/2018 1:12 AM, Manu 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. 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.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 hereYou 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()
Aug 01 2018
On Wed, 1 Aug 2018 at 03:05, Walter Bright via Digitalmars-d <digitalmars-d puremagic.com> wrote: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.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.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
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
Am Wed, 01 Aug 2018 22:13:05 -0700 schrieb Walter Bright:On 8/1/2018 12:01 PM, Manu wrote: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. -- JohannesYou'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
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: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.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
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
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
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
On 03/08/2018 9:12 AM, Walter Bright wrote:On 8/2/2018 2:05 AM, 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?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
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
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
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: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.We have demonstrated consistent ongoing issues and frustration for 6 years.Have you ever tried the alias method I proposed?
Aug 02 2018
On 8/2/2018 9:58 AM, Manu wrote:Why is it frustrating?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!
Aug 02 2018
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
On Monday, 30 July 2018 at 20:23:25 UTC, Walter Bright wrote:On 7/30/2018 9:45 AM, Manu wrote: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.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();"));Yes, please explain why you can't coalesce the namespace declarations in one C++ file into one namespace declaration.You haven't explained why you can't just move the namespace ns declarations in one file together.Are you serious?
Jul 31 2018
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
Am Wed, 01 Aug 2018 16:31:57 -0700 schrieb Walter Bright:On 7/31/2018 1:47 AM, Atila Neves wrote: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. -- JohannesThe 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.
Aug 01 2018
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
On Thursday, 2 August 2018 at 08:31:28 UTC, Walter Bright wrote:On 8/1/2018 10:06 PM, Johannes Pfau wrote: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'?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
On 8/2/18 5:26 AM, Daniel N wrote:On Thursday, 2 August 2018 at 08:31:28 UTC, Walter Bright 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. -SteveOn 8/1/2018 10:06 PM, Johannes Pfau wrote: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'?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
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. -SteveThat'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
On Thursday, 2 August 2018 at 12:30:14 UTC, rikki cattermole wrote:On 03/08/2018 12:24 AM, Steven Schveighoffer wrote:I see, thanks.I've never seen it, but it's certainly valid C++ and in the realm of possibility. -SteveThat'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
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
On Friday, 3 August 2018 at 21:20:37 UTC, Walter Bright wrote:On 8/2/2018 2:26 AM, Daniel N wrote: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.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.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?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.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.On Friday, 3 August 2018 at 21:49:53 UTC, Walter Bright wrote: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.)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!intI mean `std` should never be part of the fully qualified nameof, forinstance, `core.stdcpp.exception.std.bad_exception`. Itshould justbe `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
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 youto 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
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:Faster and consistently, sure. But I don't think 'better' is possible.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?From my experience, in many cases, C++ really doesn't express well inD 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
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: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.On Friday, 3 August 2018 at 22:55:51 UTC, Rubn wrote:Faster and consistently, sure. But I don't think 'better' is possible.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?From my experience, in many cases, C++ really doesn't express well inD 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
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: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...[...]Faster and consistently, sure. But I don't think 'better' is possible. [...]
Aug 06 2018
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: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.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.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.It would be, but I don't think it'll ever be 100% and will require manual intervention.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.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.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 youThe 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).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 04 2018
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
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: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.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
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: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.On Friday, 3 August 2018 at 22:55:51 UTC, Rubn wrote: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.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?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
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++.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.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.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
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
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
On Wednesday, 1 August 2018 at 23:31:57 UTC, Walter Bright wrote:On 7/31/2018 1:47 AM, Atila Neves wrote: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: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.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
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
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:We can also just keep the current behaviour and implement something like extern(C++, "std::chrono") in addition (as manu pointed out multiple times).[...]Good point. [...]
Aug 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 suffixI 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
On Friday, 3 August 2018 at 21:49:53 UTC, Walter Bright wrote:On 8/3/2018 3:58 AM, Atila Neves wrote: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 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 suffixI 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 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 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)`.I mean `std` should never be part of the fully qualified nameof, forinstance, `core.stdcpp.exception.std.bad_exception`. Itshould justbe `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 06 2018
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
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
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.orgThe 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
On Tuesday, 7 August 2018 at 05:58:17 UTC, Walter Bright wrote:On 8/6/2018 8:14 PM, Nicholas Wilson wrote:That is what we have been arguing for all thread...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.orgThe idea is to not have a namespaceI 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
On 8/7/2018 12:08 AM, Nicholas Wilson wrote:No, it was not. It was about making an alias to the members of the namespace.I don't see what making an alias to a namespace has to do with it.That was your suggested workaround, was it not?
Aug 07 2018
On 8/7/2018 1:13 AM, Walter Bright wrote:On 8/7/2018 12:08 AM, Nicholas Wilson wrote:BTW, the mass confusion and misunderstandings in this thread is why Manu should write a DIP.No, it was not. It was about making an alias to the members of the namespace.I don't see what making an alias to a namespace has to do with it.That was your suggested workaround, was it not?
Aug 07 2018
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
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
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
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
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:Or extern(C), or extern(C++), or extern(ObjectiveC)...On 7/29/2018 1:15 AM, Manu 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.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
On Sunday, 29 July 2018 at 08:28:08 UTC, Walter Bright wrote:On 7/29/2018 1:15 AM, Manu wrote: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.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?
Jul 29 2018
On Sunday, 29 July 2018 at 08:28:08 UTC, Walter Bright wrote:On 7/29/2018 1:15 AM, Manu wrote:FYI: this doesn't error as of now, but with https://github.com/dlang/dmd/pull/8429 it will.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
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
On 29.07.2018 09:37, Walter Bright wrote:On 7/28/2018 11:06 PM, Nicholas Wilson wrote:How would that work? I don't think this is possible.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. ...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
On Sunday, 29 July 2018 at 03:20:29 UTC, Walter Bright wrote:On 7/28/2018 11:18 AM, Manu wrote: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.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 29 2018
On Sunday, 29 July 2018 at 03:20:29 UTC, Walter Bright wrote:On 7/28/2018 11:18 AM, Manu wrote:This doesn't work for templates. If it did I wouldn't have an issue since libclang tells me what the mangling is.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 30 2018
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
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: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;On 7/28/2018 11:18 AM, Manu wrote:This doesn't work for templates. If it did I wouldn't have an issue since libclang tells me what the mangling is.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 31 2018
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: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/filesOn Sunday, 29 July 2018 at 03:20:29 UTC, Walter Bright wrote: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;On 7/28/2018 11:18 AM, Manu wrote:This doesn't work for templates. If it did I wouldn't have an issue since libclang tells me what the mangling is.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 31 2018
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: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.On Sunday, 29 July 2018 at 03:20:29 UTC, Walter Bright wrote: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;On 7/28/2018 11:18 AM, Manu wrote:This doesn't work for templates. If it did I wouldn't have an issue since libclang tells me what the mangling is.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 31 2018