digitalmars.D - Specifying C++ symbols in C++ namespaces
- Walter Bright (17/17) Apr 02 2014 Here's Andrei's proposal:
- w0rp (3/3) Apr 02 2014 Seems alright. The only downside I can think of is that the
- monnoroch (2/2) Apr 02 2014 And what about something like static struct? It seems more
- Walter Bright (3/5) Apr 02 2014 Because C++ mangles static member functions of structs differently from ...
- bearophile (18/22) Apr 02 2014 I suggest to brainstorm the syntax some more time, because
- Xiaoxi (2/25) Apr 02 2014 extern (C++) module nspace;
- bearophile (5/6) Apr 02 2014 They plan to add some kind of modules to C++ in few years :-( So
- Rikki Cattermole (6/23) Apr 02 2014 I definitely like the last two. Small and to the point. But where
- Walter Bright (19/28) Apr 02 2014 I considered that, but it fails because:
- bearophile (5/22) Apr 02 2014 Then is the idea of "extern(C++) module" by Xiaoxi usable in some
- Michel Fortin (17/38) Apr 02 2014 That's a contrived example. Perhaps I'm wrong, but I'd assume the
- Walter Bright (12/40) Apr 02 2014 Not at all. The whole point of using namespaces in C++ is to introduce a...
- Michel Fortin (81/101) Apr 03 2014 Ok, let's assume that we actually want to reproduce the C++ file
- Daniel =?ISO-8859-2?B?S2964Ws=?= (10/138) Apr 03 2014 I think we should distinguish modules lookup from namespaces lookup.
- Walter Bright (2/10) Apr 03 2014 Please, no!
- Daniel Kozak (2/14) Apr 03 2014 Ok, just an idea :)
- H. S. Teoh (13/26) Apr 03 2014 The current situation where module/scope qualifiers clash with UFCS sux,
- Walter Bright (6/10) Apr 03 2014 You have a good point in that to go all the way with namespaces, we'd ha...
- Michel Fortin (9/24) Apr 03 2014 What I'm saying is that it should be optional to create a new scope to
- Robert Clipsham (18/23) Apr 03 2014 A solution could be to allow this:
- Mike (6/25) Apr 02 2014 Walter, some on this list have not been around long enough to
- Mike (21/30) Apr 02 2014 Well, I'm assuming this is specifically for interfacing D with
- Walter Bright (2/6) Apr 02 2014 See the earlier thread entitled: "C++ interface." started yesterday.
- Kagamin (14/21) Apr 02 2014 @namespace("nspace")
- Kagamin (2/5) Apr 02 2014 std.string - does it refer to phobos module or C++ string?
- Andrej Mitrovic (6/9) Apr 03 2014 My only problem with this is how it will affect existing code. E.g.:
- Daniel Murphy (14/18) Apr 03 2014 This is really ugly and complicated.
- Andrei Alexandrescu (5/24) Apr 03 2014 I don't quite see how one is ugly and complicated and the other is...
- Daniel Murphy (18/25) Apr 03 2014 Stuff inside the template will only be instantiated when used. That's f...
- Timon Gehr (2/4) Apr 05 2014 There's good and bad taste.
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (9/9) Apr 05 2014 Not that I ever do this, but I think you need to deal with this
- =?UTF-8?B?IlRow6lv?= Bueno" (3/23) Apr 03 2014 IMO I don't think pragmas are meant to this kind of uses,
- Mason McGill (15/27) Apr 03 2014 This seems misleading to readers of future code.
- David Gileadi (3/31) Apr 04 2014 The above well describes my first reaction to the syntax (except the
- Jacob Carlborg (18/36) Apr 03 2014 I like using a UDA or pragma better:
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (5/5) Apr 03 2014 I am not sure what is the best option, but it should be readable
- deadalnix (3/22) Apr 03 2014 I'm not familiar with usual C++ mangling as much as D. Are
- Walter Bright (2/4) Apr 04 2014 No.
- deadalnix (2/6) Apr 04 2014 Then that is a bad idea.
- Dicebot (4/4) Apr 04 2014 Late to the thread, my short opinion:
- Mason McGill (7/11) Apr 04 2014 I actually remember almost trying this syntax before reading this
- Walter Bright (18/22) Apr 04 2014 Fails because:
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (2/4) Apr 04 2014 I want explicit namespaces "S::T::foo()".
- Walter Bright (3/4) Apr 04 2014 We already have a scope operator, '.', don't need another one.
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (12/13) Apr 04 2014 It is more clear to the reader that it is an external namespace
- Tove (9/25) Apr 04 2014 Why would we need new ways of declaring scopes in D? Overriding
- bearophile (4/13) Apr 04 2014 This seems promising, but this idea needs to become simpler.
- Mason McGill (38/53) Apr 04 2014 This seems like it would be simple if it came with a recommended
- Dicebot (5/22) Apr 04 2014 I don't feel this is a problem. Such foo's should be disambugated
- =?UTF-8?B?U2ltZW4gS2rDpnLDpXM=?= (14/31) Apr 04 2014 I have to say I like Robert Clipsham's idea best:
- Dicebot (5/16) Apr 04 2014 All solutions based on binding extern(C++) to some D
- =?UTF-8?B?U2ltZW4gS2rDpnLDpXM=?= (16/31) Apr 04 2014 I'm not entirely sure I follow you here. Is this what you mean?
- Dicebot (4/17) Apr 04 2014 #2 should not compile. D currently does not have any notion of
- deadalnix (2/25) Apr 04 2014 templates, function bodies, block statements, ...
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (7/10) Apr 05 2014 If you want to interface with C++ you should do it well or not at
- Dicebot (4/14) Apr 05 2014 D has own tools to disambugate symbols. Introducing new ones is
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (17/19) Apr 05 2014 I think it is primarily a notation issue. Should the notation
- Dicebot (7/10) Apr 05 2014 It shouldn't. The fact how entity is exposed via some external
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (15/18) Apr 05 2014 This is a design philosophical issue, you can make it normative
- Dicebot (8/15) Apr 05 2014 This is very practical thing. By introducing special constructs
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (4/6) Apr 05 2014 Yep, but I believe C++ is increasingly going to replace C as a
- Mason McGill (7/14) Apr 05 2014 Another way to put this is that D is its own language, not a C++
- Walter Bright (21/26) Apr 05 2014 A very good question. Some points to consider:
- Jacob Carlborg (9/11) Apr 06 2014 I think it's very low hanging fruit to add support for basic C++
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (39/42) Apr 06 2014 I think it is more important to think in term of strategic
- Walter Bright (15/17) Apr 05 2014 Yes, this seems to be a fatal flaw. Another design that has evolved from...
- Tove (9/29) Apr 05 2014 How could this common pattern look?
- Walter Bright (7/15) Apr 05 2014 extern (C++, namespace = std) {
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (4/22) Apr 06 2014 What would std be here from D's point of view? A module? Or a new
- Walter Bright (2/3) Apr 06 2014 Yes. But D has numerous methods of disambiguation.
- Michel Fortin (27/50) Apr 05 2014 I like this idea. But... should this potentially useful thing really be
- Walter Bright (8/12) Apr 05 2014 I can't escape the feeling that if you're trying to do namespaces in D, ...
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (10/15) Apr 06 2014 Namespaces are not as powerful as they could have been, but being
- Walter Bright (7/16) Apr 06 2014 It's seriously wrong to allow such. It makes a larger code base nearly
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (12/15) Apr 06 2014 Depends on how it is done. For BETA, there was a seperate
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (3/3) Apr 06 2014 Btw, cross-cutting programming is indeed meant to cater for
- monarch_dodra (42/44) Apr 06 2014 You mean UFCS? As in, for example, "front" for arrays? It doesn't
- Walter Bright (15/59) Apr 06 2014 That's a feature of a modular system, not a bug. D does not have a globa...
- Michel Fortin (16/23) Apr 06 2014 Modules are already in use on OS X for some system frameworks. It can
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (4/7) Apr 07 2014 Thanks for sharing, I wasn't aware of that. That means that clang
- Paulo Pinto (6/14) Apr 07 2014 clang developers are the ones driving the ISO C++ Modules working
- bearophile (5/22) Apr 05 2014 I suggest to keep the access to C++ namespaces as a feature for
- Michel Fortin (14/27) Apr 05 2014 What if you also have a C++ foo at global scope?
- Walter Bright (10/19) Apr 05 2014 Yes.
- Tove (20/42) Apr 06 2014 My main reservation against the new suggestion is that one would
- Adam Wilson (13/31) Apr 07 2014 This seems like a reasonable way to interop with C++ namespace in a D wa...
- Dejan Lekic (3/23) Apr 07 2014 I actually like this idea the most. It is clean, and easy to
Here's Andrei's proposal: extern (C++) template nspace() { int foo(); } It would be accessed in D by: nspace!().foo(); A possible enhancement would be to allow (for all templates with no parameters): nspace.foo(); Note that: template nspace() { extern (C++) int foo(); } would not put foo() in a C++ namespace, although it would still be accessed from D as: nspace.foo(); One downside of this proposal is that if we ever (perish the thought!) attempted to interface to C++ templates, this design would preclude that.
Apr 02 2014
Seems alright. The only downside I can think of is that the namespace wouldn't be semantically analysed until you first try to use it, as it's a template.
Apr 02 2014
And what about something like static struct? It seems more natural and less hacky to me.
Apr 02 2014
On 4/2/2014 3:30 PM, monnoroch wrote:And what about something like static struct? It seems more natural and less hacky to me.Because C++ mangles static member functions of structs differently from members of namespaces.
Apr 02 2014
On Thursday, 3 April 2014 at 01:06:25 UTC, Walter Bright wrote:Because C++ mangles static member functions of structs differently from members of namespaces.What i meant is not static functions and members of a struct, but a static struct as a concept of a struct, whith can only contain a static stuff. C++ has no such concept, but essentually static struct === namespace. Consider this: extern(C++) static struct A { static struct B { struct X {} int foo(X); } } A.B.foo(A.B.X());
Apr 02 2014
Also, D already has scope classes, so why not create full featured class bindings? Suppose, i have this: class A { private: int x; public: A(int x_) : x(x_) {} A(const A& v) : x(v.x) {} ~A() {} }; Why not interfase those as: extern (C++) { struct A { int x; this(int x_); // call c++ A::A(int) this(this); // call c++ A::A(const A&) ~this(); // call c++ A::~A() } } I mean, methods in c++ are just like functions in namespaces with first T* argument, so this is also just mangling problem; and all those constructors and destructors are not something special either. What stops to do that? If value semantics isn't appropriate, user, who writes D interface can just do it in scope class. Maby discussing that would also do some good.
Apr 02 2014
Or even the simplier way. Just do: extern(C++) struct A { int x; A A(int x_); A A(ref const(A) v); void ~A(A*); } And call those methods manually: A obj = A.A(1); A obj1 = A.A(obj); A.~A(&obj); A.~A(&obj1); The problem here it to distinguish real static methods from fake ones. But we can actually make user mark real static methods as static.
Apr 02 2014
Walter Bright:Here's Andrei's proposal: extern (C++) template nspace() { int foo(); }I suggest to brainstorm the syntax some more time, because someone could be able to invent a better syntax. Some seeds: extern (C++(nspace)) { int foo(); } extern (C++) struct nspace { int foo(); } extern (C++)(nspace) { int foo(); } extern (C++ nspace) { int foo(); } Bye, bearophile
Apr 02 2014
On Wednesday, 2 April 2014 at 22:33:21 UTC, bearophile wrote:Walter Bright:extern (C++) module nspace;Here's Andrei's proposal: extern (C++) template nspace() { int foo(); }I suggest to brainstorm the syntax some more time, because someone could be able to invent a better syntax. Some seeds: extern (C++(nspace)) { int foo(); } extern (C++) struct nspace { int foo(); } extern (C++)(nspace) { int foo(); } extern (C++ nspace) { int foo(); } Bye, bearophile
Apr 02 2014
Xiaoxi:extern (C++) module nspace;They plan to add some kind of modules to C++ in few years :-( So this risks semantic clashes. Bye, bearophile
Apr 02 2014
On Wednesday, 2 April 2014 at 22:33:21 UTC, bearophile wrote:Walter Bright:...Here's Andrei's proposal: extern (C++) template nspace() { int foo(); }I suggest to brainstorm the syntax some more time, because someone could be able to invent a better syntax. Some seeds:extern (C++)(nspace) { int foo(); } extern (C++ nspace) { int foo(); } Bye, bearophileI definitely like the last two. Small and to the point. But where nspace is a wrapper 'static struct' essentially. So: nspace.foo()
Apr 02 2014
On 4/2/2014 3:33 PM, bearophile wrote:I suggest to brainstorm the syntax some more time, because someone could be able to invent a better syntax. Some seeds: extern (C++(nspace)) { int foo(); }I considered that, but it fails because: C++: namespace S { namespace T { int foo(); namespace U { int foo(); } } } D: extern (C++, S.T) { int foo(); extern (C++, U) { int foo(); } } foo(); // error, ambiguous, which one? S.T.foo(); // S undefinedextern (C++) struct nspace { int foo(); }Fails because a struct as struct and struct as namespace are not distinguishable.
Apr 02 2014
Walter Bright:I considered that, but it fails because: C++: namespace S { namespace T { int foo(); namespace U { int foo(); } } } D: extern (C++, S.T) { int foo(); extern (C++, U) { int foo(); } } foo(); // error, ambiguous, which one? S.T.foo(); // S undefinedThen is the idea of "extern(C++) module" by Xiaoxi usable in some way? Bye, bearophile
Apr 02 2014
On 2014-04-03 01:09:43 +0000, Walter Bright <newshound2 digitalmars.com> said:I considered that, but it fails because: C++: namespace S { namespace T { int foo(); namespace U { int foo(); } } } D: extern (C++, S.T) { int foo(); extern (C++, U) { int foo(); } } foo(); // error, ambiguous, which one? S.T.foo(); // S undefinedThat's a contrived example. Perhaps I'm wrong, but I'd assume the general use case is that all functions in a module will come from the same C++ namespace. For the contrived example above, I think it's fair you have to use a contrived solution: module s.t; extern (C++, S.T): int foo(); struct U { static extern (C++, S.T.U): int foo(); } Alternatively you can use another module for the other namespace. -- Michel Fortin michel.fortin michelf.ca http://michelf.ca
Apr 02 2014
On 4/2/2014 7:14 PM, Michel Fortin wrote:On 2014-04-03 01:09:43 +0000, Walter Bright <newshound2 digitalmars.com> said:Not at all. The whole point of using namespaces in C++ is to introduce a scope. And the whole point of scopes is to have the same name in different scopes represent different objects.I considered that, but it fails because: C++: namespace S { namespace T { int foo(); namespace U { int foo(); } } } D: extern (C++, S.T) { int foo(); extern (C++, U) { int foo(); } } foo(); // error, ambiguous, which one? S.T.foo(); // S undefinedThat's a contrived example.Perhaps I'm wrong, but I'd assume the general use case is that all functions in a module will come from the same C++ namespace.I believe that is an incorrect assumption. C++ namespaces were specifically (and wrongly, in my not so humble opinion, but there it is) not designed to be closed, nor have any particular relationship with modules.For the contrived example above, I think it's fair you have to use a contrived solution:I don't believe that punishing C++ users who dare to try D is the path to success for D :-)Alternatively you can use another module for the other namespace.Forcing C++ code that exists in a single file to be split up among multiple D files is inflicting unnecessary punishment on the poor guy trying to justify migrating to D.
Apr 02 2014
On 2014-04-03 03:48:18 +0000, Walter Bright <newshound2 digitalmars.com> said:On 4/2/2014 7:14 PM, Michel Fortin wrote:Ok, let's assume that we actually want to reproduce the C++ file structure then. Let us have a C++ project, with two files. I'll temporarily use the 'namespace' keyword on the D side until we can decide on how to best represent a namespace: module foo; extern (C++): namespace S { namespace T { int foo(); namespace U { int foo(); } } } module bar; extern (C++): namespace S { namespace T { int bar(); namespace U { int bar(); } } } Now let's use those: module main; import foo; import bar; void main() { S.T.foo(); S.T.U.bar(); } But how does the lookup for those functions work? If we use structs or templates to represent those namespaces in D then you'll have to specify the module name to disambiguate the struct/template itself, and the namespace just becomes a nuisance you have to repeat over and over: void main() { .foo.S.T.foo(); .bar.S.T.U.bar(); } Here I'd argue that having whole-module namespaces in D makes no sense. So let's retry by peeling the "S.T" part of the namespace: module foo; extern (C++, S.T): int foo(); namespace U { int foo(); } module bar; extern (C++, S.T): int bar(); namespace U { int bar(); } module main; import foo; import bar; void main() { foo(); .bar.U.bar(); } Better. Still, if you want C++ namespaces to work nicely, you'll have to introduce first class namespace support in D. That means that identical namespaces are "merged" into each other when you import modules that contain them. It'd allow you to write this: void main() { foo(); U.bar(); } Still, I'm not convinced that'd be terribly helpful. Namespaces in D would make it easier to declare things 1:1 for sure, but anything that depends on Koenig lookup[1] will be broken in D. It could even be silently broken as no Koenig lookup means another function not in a namespace could be used silently instead of the expected one in a namespace (assuming a naive port of some C++ code). [1]: https://en.wikipedia.org/wiki/Argument-dependent_name_lookup I'd tend to simply implement extern(C++, namespace.here), which should work fine to wrap single-namespace cpp files, and wait to see what are the actual friction points before introducing more (people can experiment with structs or other modules meanwhile). -- Michel Fortin michel.fortin michelf.ca http://michelf.caThat's a contrived example.Not at all. The whole point of using namespaces in C++ is to introduce a scope. And the whole point of scopes is to have the same name in different scopes represent different objects.Perhaps I'm wrong, but I'd assume the general use case is that all functions in a module will come from the same C++ namespace.I believe that is an incorrect assumption. C++ namespaces were specifically (and wrongly, in my not so humble opinion, but there it is) not designed to be closed, nor have any particular relationship with modules.Alternatively you can use another module for the other namespace.Forcing C++ code that exists in a single file to be split up among multiple D files is inflicting unnecessary punishment on the poor guy trying to justify migrating to D.
Apr 03 2014
V Thu, 3 Apr 2014 06:36:54 -0400 Michel Fortin <michel.fortin michelf.ca> napsáno:On 2014-04-03 03:48:18 +0000, Walter Bright <newshound2 digitalmars.com> said:I think we should distinguish modules lookup from namespaces lookup. Something like this: A.B.foo() // call foo function from module/struct/class A and B #A.#B.foo // call foo function from namespaces A and B or A::B.foo // call foo function from namespaces A and B or /A/B.foo // call foo function from namespaces A and BOn 4/2/2014 7:14 PM, Michel Fortin wrote:Ok, let's assume that we actually want to reproduce the C++ file structure then. Let us have a C++ project, with two files. I'll temporarily use the 'namespace' keyword on the D side until we can decide on how to best represent a namespace: module foo; extern (C++): namespace S { namespace T { int foo(); namespace U { int foo(); } } } module bar; extern (C++): namespace S { namespace T { int bar(); namespace U { int bar(); } } } Now let's use those: module main; import foo; import bar; void main() { S.T.foo(); S.T.U.bar(); } But how does the lookup for those functions work? If we use structs or templates to represent those namespaces in D then you'll have to specify the module name to disambiguate the struct/template itself, and the namespace just becomes a nuisance you have to repeat over and over: void main() { .foo.S.T.foo(); .bar.S.T.U.bar(); } Here I'd argue that having whole-module namespaces in D makes no sense. So let's retry by peeling the "S.T" part of the namespace: module foo; extern (C++, S.T): int foo(); namespace U { int foo(); } module bar; extern (C++, S.T): int bar(); namespace U { int bar(); } module main; import foo; import bar; void main() { foo(); .bar.U.bar(); } Better. Still, if you want C++ namespaces to work nicely, you'll have to introduce first class namespace support in D. That means that identical namespaces are "merged" into each other when you import modules that contain them. It'd allow you to write this: void main() { foo(); U.bar(); } Still, I'm not convinced that'd be terribly helpful. Namespaces in D would make it easier to declare things 1:1 for sure, but anything that depends on Koenig lookup[1] will be broken in D. It could even be silently broken as no Koenig lookup means another function not in a namespace could be used silently instead of the expected one in a namespace (assuming a naive port of some C++ code). [1]: https://en.wikipedia.org/wiki/Argument-dependent_name_lookup I'd tend to simply implement extern(C++, namespace.here), which should work fine to wrap single-namespace cpp files, and wait to see what are the actual friction points before introducing more (people can experiment with structs or other modules meanwhile).That's a contrived example.Not at all. The whole point of using namespaces in C++ is to introduce a scope. And the whole point of scopes is to have the same name in different scopes represent different objects.Perhaps I'm wrong, but I'd assume the general use case is that all functions in a module will come from the same C++ namespace.I believe that is an incorrect assumption. C++ namespaces were specifically (and wrongly, in my not so humble opinion, but there it is) not designed to be closed, nor have any particular relationship with modules.Alternatively you can use another module for the other namespace.Forcing C++ code that exists in a single file to be split up among multiple D files is inflicting unnecessary punishment on the poor guy trying to justify migrating to D.
Apr 03 2014
On 4/3/2014 4:06 AM, Daniel Kozák wrote:I think we should distinguish modules lookup from namespaces lookup. Something like this: A.B.foo() // call foo function from module/struct/class A and B #A.#B.foo // call foo function from namespaces A and B or A::B.foo // call foo function from namespaces A and B or /A/B.foo // call foo function from namespaces A and BPlease, no!
Apr 03 2014
On Thursday, 3 April 2014 at 19:44:02 UTC, Walter Bright wrote:On 4/3/2014 4:06 AM, Daniel Kozák wrote:Ok, just an idea :)I think we should distinguish modules lookup from namespaces lookup. Something like this: A.B.foo() // call foo function from module/struct/class A and B #A.#B.foo // call foo function from namespaces A and B or A::B.foo // call foo function from namespaces A and B or /A/B.foo // call foo function from namespaces A and BPlease, no!
Apr 03 2014
On Thu, Apr 03, 2014 at 12:43:59PM -0700, Walter Bright wrote:On 4/3/2014 4:06 AM, Daniel Kozák wrote:The current situation where module/scope qualifiers clash with UFCS sux, though. static import std.algorithm; ... auto myRange = ...; //myRange.std.algorithm.find(...); // NG :-( alias find = std.algorithm.find; myRange.find(...); // OK But this is kinda tangential to this topic. :P T -- My program has no bugs! Only undocumented features...I think we should distinguish modules lookup from namespaces lookup. Something like this: A.B.foo() // call foo function from module/struct/class A and B #A.#B.foo // call foo function from namespaces A and B or A::B.foo // call foo function from namespaces A and B or /A/B.foo // call foo function from namespaces A and BPlease, no!
Apr 03 2014
On 4/3/2014 3:36 AM, Michel Fortin wrote:I'd tend to simply implement extern(C++, namespace.here), which should work fine to wrap single-namespace cpp files, and wait to see what are the actual friction points before introducing more (people can experiment with structs or other modules meanwhile).You have a good point in that to go all the way with namespaces, we'd have to implement Koenig lookup and support insertion of names into previous namespaces. I can't see this happening in D. But I don't see that as much of an argument to not do simple scoping with namespace lookup.
Apr 03 2014
On 2014-04-03 19:43:23 +0000, Walter Bright <newshound2 digitalmars.com> said:On 4/3/2014 3:36 AM, Michel Fortin wrote:Me neither.I'd tend to simply implement extern(C++, namespace.here), which should work fine to wrap single-namespace cpp files, and wait to see what are the actual friction points before introducing more (people can experiment with structs or other modules meanwhile).You have a good point in that to go all the way with namespaces, we'd have to implement Koenig lookup and support insertion of names into previous namespaces. I can't see this happening in D.But I don't see that as much of an argument to not do simple scoping with namespace lookup.What I'm saying is that it should be optional to create a new scope to declare a C++ function from a namespace. In other words you need to be able to put the function at module scope in D. -- Michel Fortin michel.fortin michelf.ca http://michelf.ca
Apr 03 2014
On Thursday, 3 April 2014 at 03:48:08 UTC, Walter Bright wrote:A solution could be to allow this: ---- module foo { module bar { // equivalent to foo/bar.d } } extern(C++) module bar { // Equivalent to namespace bar {} in C++ } ---- Note that Rust does something similar to this to allow multiple modules to be defined in a single file (though Rust also doesn't have the correspondence between filesystem location and module like D does - perhaps this is acceptable with the introduction of package.d?) RobertAlternatively you can use another module for the other namespace.Forcing C++ code that exists in a single file to be split up among multiple D files is inflicting unnecessary punishment on the poor guy trying to justify migrating to D.
Apr 03 2014
On Wednesday, 2 April 2014 at 22:06:53 UTC, Walter Bright wrote:Here's Andrei's proposal: extern (C++) template nspace() { int foo(); } It would be accessed in D by: nspace!().foo(); A possible enhancement would be to allow (for all templates with no parameters): nspace.foo(); Note that: template nspace() { extern (C++) int foo(); } would not put foo() in a C++ namespace, although it would still be accessed from D as: nspace.foo(); One downside of this proposal is that if we ever (perish the thought!) attempted to interface to C++ templates, this design would preclude that.Walter, some on this list have not been around long enough to understand the motivation for this. Could you please summarize the problem and how this addresses it? Is this for interfacing D to C++, or a way to bring namespace semantics to D? Mike
Apr 02 2014
On Wednesday, 2 April 2014 at 23:04:58 UTC, Mike wrote:On Wednesday, 2 April 2014 at 22:06:53 UTC, Walter Bright wrote:Well, I'm assuming this is specifically for interfacing D with C++ given the 'extern (C++)' attribution. In that case, I think the proposal abuses the 'template' keyword for something that's not really a template. In that case, I find the syntax proposed by bearophile to be far better... extern (C++ nspace) { int foo(); } ...although I would even prefer it be even more explicit... extern (C++ namespace nspace) { int foo(); } I'd also be interested in hearing the arguments against the UDAs and pragmas proposed in the following two links: * https://d.puremagic.com/issues/show_bug.cgi?id=7961 * https://github.com/D-Programming-Language/dmd/pull/2767 The pragma is especially nice since this isn't really a D thing, although bearophile's proposed syntax is hard to argue against. MikeHere's Andrei's proposal: extern (C++) template nspace() { int foo(); }Is this for interfacing D to C++, or a way to bring namespace semantics to D?
Apr 02 2014
On 4/2/2014 4:04 PM, Mike wrote:Walter, some on this list have not been around long enough to understand the motivation for this. Could you please summarize the problem and how this addresses it? Is this for interfacing D to C++, or a way to bring namespace semantics to D?See the earlier thread entitled: "C++ interface." started yesterday.
Apr 02 2014
On Wednesday, 2 April 2014 at 22:06:53 UTC, Walter Bright wrote:Here's Andrei's proposal: extern (C++) template nspace() { int foo(); }namespace("nspace") extern (C++) { int foo(); }One downside of this proposal is that if we ever (perish the thought!) attempted to interface to C++ templates, this design would preclude that.If we have partial C++ bindings, why not have partial template bindings with a subset of features already existing in D? With that you would only need to implement mangling and linking. An interesting and simple enough use case is casting: extern(C++) T my_cast(T,U)(U); extern(C++) interface A{} extern(C++) interface B:A{} A a; B b = my_cast!B(a);
Apr 02 2014
On Wednesday, 2 April 2014 at 22:06:53 UTC, Walter Bright wrote:A possible enhancement would be to allow (for all templates with no parameters): nspace.foo();std.string - does it refer to phobos module or C++ string?
Apr 02 2014
On 4/3/14, Walter Bright <newshound2 digitalmars.com> wrote:A possible enhancement would be to allow (for all templates with no parameters): nspace.foo();My only problem with this is how it will affect existing code. E.g.: template take(alias templ) { } template take(T) { } template Empty() { struct Empty { } } take!Empty; // which overload of take is instantiated?
Apr 03 2014
"Walter Bright" wrote in message news:lhi1lt$269h$1 digitalmars.com...Here's Andrei's proposal: extern (C++) template nspace() { int foo(); }This is really ugly and complicated. Why not just pragma(cpp_namespace, "outer") { pragma(cpp_namespace, "inner") { extern(C++) void func(); } } which is trivial to implement and doesn't require parser or semantic changes? Adding syntax for actual namespaces to D is a different beast and IMO not worthwhile.
Apr 03 2014
On 4/3/14, 4:19 AM, Daniel Murphy wrote:"Walter Bright" wrote in message news:lhi1lt$269h$1 digitalmars.com...I don't quite see how one is ugly and complicated and the other is... pretty and simple? Anyhow de gustibus.Here's Andrei's proposal: extern (C++) template nspace() { int foo(); }This is really ugly and complicated. Why not just pragma(cpp_namespace, "outer") { pragma(cpp_namespace, "inner") { extern(C++) void func(); } } which is trivial to implement and doesn't require parser or semantic changes?Adding syntax for actual namespaces to D is a different beast and IMO not worthwhile.Agreed. Andrei
Apr 03 2014
"Andrei Alexandrescu" wrote in message news:lhkebg$1i1p$1 digitalmars.com...extern (C++) template nspace() { int foo(); }This is really ugly and complicated.I don't quite see how one is ugly and complicated and the other is... pretty and simple? Anyhow de gustibus.Stuff inside the template will only be instantiated when used. That's fine when it's just a prototype of a C++ function to be called from D, but much less useful when the implementation is in D and the use is from C++. It can conflict with the eponymous template syntax - D would not be able to tell the difference between a templated function and a function inside a namespace with the same name. It forces this organisation for all symbols that use C++ namespaces. If you define functions in the same namespace in different modules the template symbols will conflict and you will have to use fully-qualified names. On the other side, in D modules are used for symbol organisation. It's powerful enough that you can get namespace::function to match library.module.function (and I expect you can force use of the namespace through clever use of static renamed imports). The missing part is getting the mangling right, and a pragma is the least intrusive way I can imagine to do that.
Apr 03 2014
On 04/03/2014 09:55 PM, Andrei Alexandrescu wrote:... Anyhow de gustibus.There's good and bad taste.
Apr 05 2014
Not that I ever do this, but I think you need to deal with this C++ construct: namespace exposed_ns { using namespace internal_ns_2134zxdssdffrandomblablah; using namespace internal_ns_2634zasdsfsdrandomblablah; using namespace internal_ns_2993adsfadsfrandomblablah; } To do this in D you would have to be able to set up a search sequence as an alias somehow.
Apr 05 2014
On Thursday, 3 April 2014 at 11:19:53 UTC, Daniel Murphy wrote:"Walter Bright" wrote in message news:lhi1lt$269h$1 digitalmars.com...IMO I don't think pragmas are meant to this kind of uses, extern(C++) already exists and makes more sense.Here's Andrei's proposal: extern (C++) template nspace() { int foo(); }This is really ugly and complicated. Why not just pragma(cpp_namespace, "outer") { pragma(cpp_namespace, "inner") { extern(C++) void func(); } } which is trivial to implement and doesn't require parser or semantic changes? Adding syntax for actual namespaces to D is a different beast and IMO not worthwhile.
Apr 03 2014
"Walter Bright" wrote in message news:lhi1lt$269h$1 digitalmars.com...Here's Andrei's proposal: extern (C++) template nspace() { int foo(); }This seems misleading to readers of future code. - An "extern (C++)" function lets you use a C++ function. - An "extern (C++)" interface lets you use a C++ interface (declared as a class, as is always the case in C++). - An "extern (C++)" template lets you use a C++... namespace? On Thursday, 3 April 2014 at 11:19:53 UTC, Daniel Murphy wrote:Why not just pragma(cpp_namespace, "outer") { pragma(cpp_namespace, "inner") { extern(C++) void func(); } }This really has only one obvious interpretation (the correct one), and seems to be a rather harmless addition to the language. It also fulfills the goal of allowing access to C++ libraries without cluttering D with C++ language features. I don't want to have to explain to my students the difference between "modules" "D templates" and "C++ namespace templates" (it reminds me of old- and new-style classes in Python 2).
Apr 03 2014
On 4/3/14, 11:59 PM, Mason McGill wrote:"Walter Bright" wrote in message news:lhi1lt$269h$1 digitalmars.com...The above well describes my first reaction to the syntax (except the part about having students). And my second reaction too, in fact.Here's Andrei's proposal: extern (C++) template nspace() { int foo(); }This seems misleading to readers of future code. - An "extern (C++)" function lets you use a C++ function. - An "extern (C++)" interface lets you use a C++ interface (declared as a class, as is always the case in C++). - An "extern (C++)" template lets you use a C++... namespace? On Thursday, 3 April 2014 at 11:19:53 UTC, Daniel Murphy wrote:Why not just pragma(cpp_namespace, "outer") { pragma(cpp_namespace, "inner") { extern(C++) void func(); } }This really has only one obvious interpretation (the correct one), and seems to be a rather harmless addition to the language. It also fulfills the goal of allowing access to C++ libraries without cluttering D with C++ language features. I don't want to have to explain to my students the difference between "modules" "D templates" and "C++ namespace templates" (it reminds me of old- and new-style classes in Python 2).
Apr 04 2014
On 03/04/14 00:07, Walter Bright wrote:Here's Andrei's proposal: extern (C++) template nspace() { int foo(); } It would be accessed in D by: nspace!().foo(); A possible enhancement would be to allow (for all templates with no parameters): nspace.foo(); Note that: template nspace() { extern (C++) int foo(); } would not put foo() in a C++ namespace, although it would still be accessed from D as: nspace.foo(); One downside of this proposal is that if we ever (perish the thought!) attempted to interface to C++ templates, this design would preclude that.I like using a UDA or pragma better: namespace("nspace") { extern (C++) int foo (); } Or pragma(cpp_namespace, "nspace") { extern (C++) int foo (); } Then it's also possible to use this syntax: namespace("nspace"): extern (C++) int foo (); The only advantage I can see with using "template" is that templates can be mixed in, it would be similar to the using declarative in C++. -- /Jacob Carlborg
Apr 03 2014
I am not sure what is the best option, but it should be readable and obvious. So I might prefer to just have "::" if possible. Somewhat annoying and verbose, so I am not sure about this, but the advantage is that it is easy to see what is C++ and what is D function calls.
Apr 03 2014
On Wednesday, 2 April 2014 at 22:06:53 UTC, Walter Bright wrote:Here's Andrei's proposal: extern (C++) template nspace() { int foo(); } It would be accessed in D by: nspace!().foo(); A possible enhancement would be to allow (for all templates with no parameters): nspace.foo(); Note that: template nspace() { extern (C++) int foo(); } would not put foo() in a C++ namespace, although it would still be accessed from D as: nspace.foo(); One downside of this proposal is that if we ever (perish the thought!) attempted to interface to C++ templates, this design would preclude that.I'm not familiar with usual C++ mangling as much as D. Are template and namespace mangled the same way ?
Apr 03 2014
On 4/3/2014 5:47 PM, deadalnix wrote:I'm not familiar with usual C++ mangling as much as D. Are template and namespace mangled the same way ?No.
Apr 04 2014
On Friday, 4 April 2014 at 07:06:30 UTC, Walter Bright wrote:On 4/3/2014 5:47 PM, deadalnix wrote:Then that is a bad idea.I'm not familiar with usual C++ mangling as much as D. Are template and namespace mangled the same way ?No.
Apr 04 2014
Late to the thread, my short opinion: extern(C++ namespace::path) looks best. It should only affect mangling and have no impact on fully qualified name on D side. Most KISS solution I have read in the thread.
Apr 04 2014
On Friday, 4 April 2014 at 12:34:15 UTC, Dicebot wrote:Late to the thread, my short opinion: extern(C++ namespace::path) looks best. It should only affect mangling and have no impact on fully qualified name on D side. Most KISS solution I have read in the thread.I actually remember almost trying this syntax before reading this thread. It's definitely intuitive, and it KIS. Though, may I suggest extern(C++, namespace::path) or extern(C++, namespace, path) keeping in line with __traits and pragma?
Apr 04 2014
On 4/4/2014 5:34 AM, Dicebot wrote:Late to the thread, my short opinion: extern(C++ namespace::path) looks best. It should only affect mangling and have no impact on fully qualified name on D side. Most KISS solution I have read in the thread.Fails because: C++: namespace S { namespace T { int foo(); namespace U { int foo(); } } } D: extern (C++, S::T) { int foo(); extern (C++, U) { int foo(); } } foo(); // error, ambiguous, which one? S.T.foo(); // S undefined
Apr 04 2014
On Friday, 4 April 2014 at 19:43:56 UTC, Walter Bright wrote:foo(); // error, ambiguous, which one? S.T.foo(); // S undefinedI want explicit namespaces "S::T::foo()".
Apr 04 2014
On 4/4/2014 1:00 PM, "Ola Fosheim Grøstad" <ola.fosheim.grostad+dlang gmail.com>" wrote:I want explicit namespaces "S::T::foo()".We already have a scope operator, '.', don't need another one.
Apr 04 2014
On Friday, 4 April 2014 at 20:06:49 UTC, Walter Bright wrote:We already have a scope operator, '.', don't need another one.It is more clear to the reader that it is an external namespace and you avoid renaming because then C++ has it's own namespace in D reducing the chances of clashes. But it's a minor issue, although I think it is important for long term maintainability of code to easily discriminate between C++ function calls (which tend to be supportive lower level libraries/engines) and D function calls (which tend to be higher level code). When you do contract work on many projects for different small businesses, you often get requests for modifications/additions 1-2 times a year or so. The less chance of code misinterpretation, the better.
Apr 04 2014
On Friday, 4 April 2014 at 19:43:56 UTC, Walter Bright wrote:C++: namespace S { namespace T { int foo(); namespace U { int foo(); } } } D: extern (C++, S::T) { int foo(); extern (C++, U) { int foo(); } } foo(); // error, ambiguous, which one? S.T.foo(); // S undefinedWhy would we need new ways of declaring scopes in D? Overriding the external mangling should be sufficient? If there are collisions you can use any type of scope you prefer to avoid the issue, modules, structs, templates, even functions or blocks... void fun1() { extern (C++, S::T) int foo();} void fun2() { extern (C++, S::T::U) int foo();} extern (C++, S::T::U) int foo(); struct test { extern (C++, S::T) int foo();}
Apr 04 2014
Tove:Why would we need new ways of declaring scopes in D? Overriding the external mangling should be sufficient? If there are collisions you can use any type of scope you prefer to avoid the issue, modules, structs, templates, even functions or blocks... void fun1() { extern (C++, S::T) int foo();} void fun2() { extern (C++, S::T::U) int foo();} extern (C++, S::T::U) int foo(); struct test { extern (C++, S::T) int foo();}This seems promising, but this idea needs to become simpler. Bye, bearophile
Apr 04 2014
On Friday, 4 April 2014 at 21:39:01 UTC, bearophile wrote:Tove:This seems like it would be simple if it came with a recommended style for library wrappers, e.g. // C++ namespace A { namespace B { void f1(); void f2(); } namespace C { void f3(); void f4(); } } // D struct A { struct B { extern(C++, A, B): static void f1(); static void f2(); } struct C { extern(C++, A, C): static void f3(); static void f4(); } } This can be easily generated by hand or with something like SWIG, and keeps the semantics of "extern" consistent throughout the language (it still only affects the ABI). This also keeps things simple for users who just want to call one function. // D void callF1() { extern(C++, A, B) void f1(); f1(); } I used "," instead of "::" because it avoids adding a new token, but that's more of an aesthetic issue.Why would we need new ways of declaring scopes in D? Overriding the external mangling should be sufficient? If there are collisions you can use any type of scope you prefer to avoid the issue, modules, structs, templates, even functions or blocks... void fun1() { extern (C++, S::T) int foo();} void fun2() { extern (C++, S::T::U) int foo();} extern (C++, S::T::U) int foo(); struct test { extern (C++, S::T) int foo();}This seems promising, but this idea needs to become simpler. Bye, bearophile
Apr 04 2014
On Friday, 4 April 2014 at 19:43:56 UTC, Walter Bright wrote:Fails because: C++: namespace S { namespace T { int foo(); namespace U { int foo(); } } } D: extern (C++, S::T) { int foo(); extern (C++, U) { int foo(); } } foo(); // error, ambiguous, which one? S.T.foo(); // S undefinedI don't feel this is a problem. Such foo's should be disambugated by D tools, which means using different modules. Exact matching between C++ and D sources is impossible anyway, it is not worth complicating D qualification system for that.
Apr 04 2014
On 03.04.2014 00:07, Walter Bright wrote:Here's Andrei's proposal: extern (C++) template nspace() { int foo(); } It would be accessed in D by: nspace!().foo(); A possible enhancement would be to allow (for all templates with no parameters): nspace.foo(); Note that: template nspace() { extern (C++) int foo(); } would not put foo() in a C++ namespace, although it would still be accessed from D as: nspace.foo(); One downside of this proposal is that if we ever (perish the thought!) attempted to interface to C++ templates, this design would preclude that.I have to say I like Robert Clipsham's idea best: extern(C++) module nspace { int foo(); // Is this also extern(C++)? I think it should be. } extern(C++) module nspace { module innernspace { int bar(); // Also extern(C++), if we follow the example above. } } I haven't the foggiest idea how C++ modules are supposed to work, so there might be clashes with those somehow? -- Simen
Apr 04 2014
On Friday, 4 April 2014 at 18:51:21 UTC, Simen Kjærås wrote:I have to say I like Robert Clipsham's idea best: extern(C++) module nspace { int foo(); // Is this also extern(C++)? I think it should be. } extern(C++) module nspace { module innernspace { int bar(); // Also extern(C++), if we follow the example above. } }All solutions based on binding extern(C++) to some D qualification entity are bad because they confuse reader into thinking that `bar` is actually `nspace.innerspace.bar` and that should never happen.
Apr 04 2014
On 04.04.2014 20:54, Dicebot wrote:On Friday, 4 April 2014 at 18:51:21 UTC, Simen Kjærås wrote:I'm not entirely sure I follow you here. Is this what you mean? extern(C++) module nspace { int foo(); } void main() { } then alias foo = nspace.foo; If I'm far off into the fields of ignorance now, care to show me the way to a better understanding? -- SimenI have to say I like Robert Clipsham's idea best: extern(C++) module nspace { int foo(); // Is this also extern(C++)? I think it should be. } extern(C++) module nspace { module innernspace { int bar(); // Also extern(C++), if we follow the example above. } }All solutions based on binding extern(C++) to some D qualification entity are bad because they confuse reader into thinking that `bar` is actually `nspace.innerspace.bar` and that should never happen.
Apr 04 2014
On Friday, 4 April 2014 at 19:33:34 UTC, Simen Kjærås wrote:I'm not entirely sure I follow you here. Is this what you mean? extern(C++) module nspace { int foo(); } void main() { } If so, is that really bad? I'd say the better choice is to make alias foo = nspace.foo; If I'm far off into the fields of ignorance now, care to show me the way to a better understanding?namespaces other than modules / aggregates and I am against introducing those just for the sake of interfacing with C++.
Apr 04 2014
On Friday, 4 April 2014 at 22:17:45 UTC, Dicebot wrote:On Friday, 4 April 2014 at 19:33:34 UTC, Simen Kjærås wrote:templates, function bodies, block statements, ...I'm not entirely sure I follow you here. Is this what you mean? extern(C++) module nspace { int foo(); } void main() { } If so, is that really bad? I'd say the better choice is to alias: alias foo = nspace.foo; If I'm far off into the fields of ignorance now, care to show me the way to a better understanding?namespaces other than modules / aggregates and I am against introducing those just for the sake of interfacing with C++.
Apr 04 2014
On Friday, 4 April 2014 at 22:17:45 UTC, Dicebot wrote:namespaces other than modules / aggregates and I am against introducing those just for the sake of interfacing with C++.If you want to interface with C++ you should do it well or not at all. In C++ namespace names reside in their own namespace which means that you get short names like "std", "qt" etc. Which in turn means you have to rename those to "CPPstd", "CPPqt" etc in D in order to disambiguate the symbols. Having a dedicated namespace operator would be a lot more convenient.
Apr 05 2014
On Saturday, 5 April 2014 at 08:42:27 UTC, Ola Fosheim Grøstad wrote:On Friday, 4 April 2014 at 22:17:45 UTC, Dicebot wrote:D has own tools to disambugate symbols. Introducing new ones is equivalent to admitting D module system does not work by design.namespaces other than modules / aggregates and I am against introducing those just for the sake of interfacing with C++.If you want to interface with C++ you should do it well or not at all. In C++ namespace names reside in their own namespace which means that you get short names like "std", "qt" etc. Which in turn means you have to rename those to "CPPstd", "CPPqt" etc in D in order to disambiguate the symbols. Having a dedicated namespace operator would be a lot more convenient.
Apr 05 2014
On Saturday, 5 April 2014 at 12:07:36 UTC, Dicebot wrote:D has own tools to disambugate symbols. Introducing new ones is equivalent to admitting D module system does not work by design.I think it is primarily a notation issue. Should the notation help you discern what is C++ and what is D, or do you have to memorize symbols? How much extra notational work is it acceptable to impose on the programmer? There are advantages and disadvantages to both approaches. Pro explicit c++ namespaces: - Easy to discern what is C++ and what is D. - Less chance of future irreconcilable design conflicts when either C++ or D changes (e.g. C++18 and beyond) - Having a philosophy of "native foreign functions" rather than "masquerading as D constructs" makes it easier to integrate with other languages beyond c/c++ at a later stage. Con: - More syntax to understand for newbies - Requires a little bit more refactoring when moving C++ code to D.
Apr 05 2014
On Saturday, 5 April 2014 at 12:30:28 UTC, Ola Fosheim Grøstad wrote:Should the notation help you discern what is C++ and what is D, or do you have to memorize symbols? How much extra notational work is it acceptable to impose on the programmer?It shouldn't. The fact how entity is exposed via some external binary interface should not have any notable impact on D side of things (unless you dwell into ABI realm). This is exactly what "extern" is for - matching symbols from domain of D terms to some external alien domain.
Apr 05 2014
On Saturday, 5 April 2014 at 12:58:54 UTC, Dicebot wrote:It shouldn't. The fact how entity is exposed via some external binary interface should not have any notable impact on D side of things (unless you dwell into ABI realm).This is a design philosophical issue, you can make it normative if you want, but only if it is consistent with the overall design philosophy. Working on making that philosophy explicit is important, D2 is showing some signs of having gone through a lot of evolutionary design and IMHO signs of a need for notational redesign. Meaning: recreate the syntax to fit the desired semantics that the language has obtained over time (as in designing it, not evolving). Not distinguishing between C++/D does however have consequences: if foreign constructs have the same appearance as the language constructs then you should also make sure that all the semantics are the same. E.g. C++ exceptions, calls to C++ new etc have to be fully harmonized with D equivalents.
Apr 05 2014
On Saturday, 5 April 2014 at 13:11:27 UTC, Ola Fosheim Grøstad wrote:On Saturday, 5 April 2014 at 12:58:54 UTC, Dicebot wrote:This is very practical thing. By introducing special constructs to support some foreign language you open the can of worms. Where does one stop? Should we also expect adding some new idioms for better JNI support? Or Python? I can't see any reason why C++ has to be any special and you can't nicely support them all. We don't even truly do this for C and this the only real ABI standard.It shouldn't. The fact how entity is exposed via some external binary interface should not have any notable impact on D side of things (unless you dwell into ABI realm).This is a design philosophical issue, you can make it normative if you want, but only if it is consistent with the overall design philosophy.
Apr 05 2014
On Saturday, 5 April 2014 at 15:24:32 UTC, Dicebot wrote:This is very practical thing. By introducing special constructs to support some foreign language you open the can of worms.Yep, but I believe C++ is increasingly going to replace C as a language for writing basic libraries and engines in the next few decades. Which isn't great for interop, but a trend still.
Apr 05 2014
On Saturday, 5 April 2014 at 15:24:32 UTC, Dicebot wrote:This is very practical thing. By introducing special constructs to support some foreign language you open the can of worms. Where does one stop? Should we also expect adding some new idioms for better JNI support? Or Python? I can't see any reason why C++ has to be any special and you can't nicely support them all. We don't even truly do this for C and this the only real ABI standard.Another way to put this is that D is its own language, not a C++ extension. IMO, an FFI should make interoperability possible via ABI matching, but it should not compromise the language (by making its scoping rules more complicated, introducing redundant constructs, or introducing a new token ("::") that could be used for another feature).
Apr 05 2014
On 4/5/2014 8:24 AM, Dicebot wrote:This is very practical thing. By introducing special constructs to support some foreign language you open the can of worms. Where does one stop? Should we also expect adding some new idioms for better JNI support? Or Python? I can't see any reason why C++ has to be any special and you can't nicely support them all. We don't even truly do this for C and this the only real ABI standard.A very good question. Some points to consider: 1. D is supposed to be a practical language, and be designed to get s**t done. 2. D has long recognized that C++ exists and tries to be accommodating - with extern(C++) and C++ compatible COM classes. extern(C++) already does more than just adjust the name mangling. 3. There's significant demand for supporting C++ namespaces among people trying to migrate to D. There's more than just the people who post here. Currently, this is a barrier to adoption of D, and an unnecessary one. 4. I know I very much appreciate products that don't try and pretend they are the shiznit and nothing else exists. For example, Thunderbird Mail was able to import my old Outlook Express database perfectly, enabling me to completely abandon OE. 5. There's also work underway to better integrate with ObjectiveC. In the light of that: 1. We cannot nicely support them all. But we don't have to. We can support the low hanging fruit. 2. C++ namespaces are very low hanging fruit, with a significant payoff. It's worthwhile. 3. C++ is special because a) we can support limited interoperability without much effort and b) a lot of people come to D from C++ and want to interoperate.
Apr 05 2014
On 2014-04-05 22:42, Walter Bright wrote:2. C++ namespaces are very low hanging fruit, with a significant payoff. It's worthwhile.I think it's very low hanging fruit to add support for basic C++ namespaces. Support for basically just set the mangled name in a somewhat nice way, a pragma for example. If we're talking about adding something more advanced like "::" or "extern (C++) template" which my affect the current name look up rules then I don't think that's so low hanging fruit anymore. -- /Jacob Carlborg
Apr 06 2014
I think it's very low hanging fruit to add support for basic C++ namespaces. Support for basically just set the mangled name in a somewhat nice way, a pragma for example.I think it is more important to think in term of strategic positions than whether it takes 1 or 2 weeks to implement a feature. Assumption: It is desirable to make the eco system more attractive for commercial projects. Key requirements: - Long term stability of the dev environment. - Access to mature libraries with significant backing (basically C/C++ libraries). - Easy integration with existing technology and systems (basically C/C++). - No lock-in (basically C/C++ interop). - Predictable dev environment that enables precise cost estimates. - Lowering costs/faster development than the alternatives (more convinient than C/C++) If you cannot assume that you can utilize a C++ library from D or if you have to assume that using a C++ library might incur a significant interfacing overhead (in terms of programmer's time) then D looks like a more risky proposition. The key difference between a commercial project and a hobby project is that the hobby project can fully adapt the requirements to the dev environment. A hobbyist game project can settle for a less capable physics engine or create a custom one, for fun. A commercial project will view that as costs that cut into profit margins and a potential source of failure in the market. That's a good reason to go with C++ instead of D. From a strategic point of view it is important to fully support those features you claim to support. If you can claim that interfacing with C++, except for templates, is easy, then you communicate that it is relatively easy to assess project costs. If you only claim that it is possible to interface with some of C++, but that it is kind of difficult under certain vaguely specified circumstances then I think you should wait until you have a better solution. What you absolutely don't want is to trick people into thinking that interfacing with C++ is easy, if it isn't, and have them discover that they are better off dumping D and doing it all over in C++.
Apr 06 2014
On 4/2/2014 3:07 PM, Walter Bright wrote:One downside of this proposal is that if we ever (perish the thought!) attempted to interface to C++ templates, this design would preclude that.Yes, this seems to be a fatal flaw. Another design that has evolved from these discussions and my discussions with Andrei on it: extern (C++, namespace = A.B) { void foo(); void bar(); } extern (C++, namespace = C) void foo(); bar(); // works A.B.bar(); // works foo(); // error: ambiguous C.foo(); // works alias C.foo foo; foo(); // works, calling C.foo() I really think the namespace semantics should be attached to the extern(C++) rather than be a separate pragma. Having the namespace= thing means that namespace isn't a keyword, and provides a general mechanism where we can add language specific information as necessary.
Apr 05 2014
On Saturday, 5 April 2014 at 20:47:29 UTC, Walter Bright wrote:On 4/2/2014 3:07 PM, Walter Bright wrote:How could this common pattern look? std::string boost::fun(std::string arg) alias cpp = extern (C++, namespace = std); alias boost = extern (C++, namespace = boost); cpp.string boost.fun(cpp.string arg) ?One downside of this proposal is that if we ever (perish the thought!) attempted to interface to C++ templates, this design would preclude that.Yes, this seems to be a fatal flaw. Another design that has evolved from these discussions and my discussions with Andrei on it: extern (C++, namespace = A.B) { void foo(); void bar(); } extern (C++, namespace = C) void foo(); bar(); // works A.B.bar(); // works foo(); // error: ambiguous C.foo(); // works alias C.foo foo; foo(); // works, calling C.foo() I really think the namespace semantics should be attached to the extern(C++) rather than be a separate pragma. Having the namespace= thing means that namespace isn't a keyword, and provides a general mechanism where we can add language specific information as necessary.
Apr 05 2014
On 4/5/2014 2:31 PM, Tove wrote:How could this common pattern look? std::string boost::fun(std::string arg) alias cpp = extern (C++, namespace = std); alias boost = extern (C++, namespace = boost); cpp.string boost.fun(cpp.string arg) ?extern (C++, namespace = std) { struct string { ... } } extern (C++, namespace = boost) { void fun(std.string arg); }
Apr 05 2014
On Saturday, 5 April 2014 at 21:43:03 UTC, Walter Bright wrote:On 4/5/2014 2:31 PM, Tove wrote:What would std be here from D's point of view? A module? Or a new kind of symbol? And wouldn't it clash with D's std package?How could this common pattern look? std::string boost::fun(std::string arg) alias cpp = extern (C++, namespace = std); alias boost = extern (C++, namespace = boost); cpp.string boost.fun(cpp.string arg) ?extern (C++, namespace = std) { struct string { ... } } extern (C++, namespace = boost) { void fun(std.string arg); }
Apr 06 2014
On 4/6/2014 2:56 AM, "Marc Schütz" <schuetzm gmx.net>" wrote:And wouldn't it clash with D's std package?Yes. But D has numerous methods of disambiguation.
Apr 06 2014
On 2014-04-05 20:47:32 +0000, Walter Bright <newshound2 digitalmars.com> said:On 4/2/2014 3:07 PM, Walter Bright wrote:I like this idea. But... should this potentially useful thing really be restricted to extern C++ things? I've seen at least one attempt to create a namespace using what D currently offers [1], and frankly something like the above would make much more sense than a class no one can instantiate. Here's a suggestion: namespace A.B { // can create two levels at once, yeah! void foo(); void bar(); } namespace C { void foo(); } Make those C++ declarations, it does not look too foreign anymore: extern (C++) namespace A.B { void foo(); void bar(); } extern (C++) namespace C { void foo(); } -- Michel Fortin michel.fortin michelf.ca http://michelf.caOne downside of this proposal is that if we ever (perish the thought!) attempted to interface to C++ templates, this design would preclude that.Yes, this seems to be a fatal flaw. Another design that has evolved from these discussions and my discussions with Andrei on it: extern (C++, namespace = A.B) { void foo(); void bar(); } extern (C++, namespace = C) void foo(); bar(); // works A.B.bar(); // works foo(); // error: ambiguous C.foo(); // works alias C.foo foo; foo(); // works, calling C.foo() I really think the namespace semantics should be attached to the extern(C++) rather than be a separate pragma. Having the namespace= thing means that namespace isn't a keyword, and provides a general mechanism where we can add language specific information as necessary.
Apr 05 2014
On 4/5/2014 2:55 PM, Michel Fortin wrote:I like this idea. But... should this potentially useful thing really be restricted to extern C++ things? I've seen at least one attempt to create a namespace using what D currently offers [1], and frankly something like the above would make much more sense than a class no one can instantiate.I can't escape the feeling that if you're trying to do namespaces in D, you're doing something worng. I feel that C++ messed up namespace design because: 1. namespaces are not closed 2. they have no relationship with modules which has wound up forcing the addition of Yet Another Design when imports and modules are added to C++.
Apr 05 2014
On Saturday, 5 April 2014 at 23:26:30 UTC, Walter Bright wrote:I feel that C++ messed up namespace design because: 1. namespaces are not closed 2. they have no relationship with modulesNamespaces are not as powerful as they could have been, but being able to add symbols to an external scope (like classes) is very useful if done right (e.g. cross-cutting enhancements, adding members to external classes like "saveyourself", "printyourself").which has wound up forcing the addition of Yet Another Design when imports and modules are added to C++.Unfortunately that seems to be years into the future? Although clang has begun implementing something: http://clang.llvm.org/docs/Modules.html I've got at feeling that if clang gets something working it will become a de-facto standard due to demand.
Apr 06 2014
On 4/6/2014 12:39 PM, "Ola Fosheim Grøstad" <ola.fosheim.grostad+dlang gmail.com>" wrote:On Saturday, 5 April 2014 at 23:26:30 UTC, Walter Bright wrote:It's seriously wrong to allow such. It makes a larger code base nearly impossible to reliably reason about, leading one to rely on conventions like "don't add stuff to namespaces". D has closed scopes, and members can be "added" to external classes just fine, using CTFE.I feel that C++ messed up namespace design because: 1. namespaces are not closed 2. they have no relationship with modulesNamespaces are not as powerful as they could have been, but being able to add symbols to an external scope (like classes) is very useful if done right (e.g. cross-cutting enhancements, adding members to external classes like "saveyourself", "printyourself").
Apr 06 2014
On Sunday, 6 April 2014 at 20:17:09 UTC, Walter Bright wrote:It's seriously wrong to allow such. It makes a larger code base nearly impossible to reliably reason about, leading one to rely on conventions like "don't add stuff to namespaces".Depends on how it is done. For BETA, there was a seperate "fragment system" that allowed AST specified extension points. This system was used for both extensions and for encapsulation/API definition. You basically defined "slots" in the syntax three where code could be injected (following the grammar of the slot) and what should be hidden etc. It was simplistic elegance IMO: http://www.cs.au.dk/~beta/Manuals/latest/beta/fragment.html The weakness was that they didn't allow for dynamic dispatch (required static resolution), but that was an implementation issue, I think.
Apr 06 2014
Btw, cross-cutting programming is indeed meant to cater for programming in the large: http://en.wikipedia.org/wiki/Aspect-oriented_programming
Apr 06 2014
On Sunday, 6 April 2014 at 20:17:09 UTC, Walter Bright wrote:D has closed scopes, and members can be "added" to external classes just fine, using CTFE.You mean UFCS? As in, for example, "front" for arrays? It doesn't work as well as advertised though. The issue is that the added members are only visible if the *called* code knows to import the *caller* code. This breaks as soon as you leave your own internal ecosystem. //---- import a; struct S //Some object { } //Extend to make it a range. bool empty(S); int front(S); void popFront(S); //Try it. void main() { S s; foreach(e; s) //Error: invalid foreach aggregate s writeln(s); s.array(); //Error: template std.range.take cannot... a.foo(s); //Error: no property 'popFront' for type 'S' } //---- module a; void foo(T)(T t) { t.popFront(); } //---- Well that horribly fails. Because when calling a template, you are only importing the passed argument, but not his ecosystem with it. The only way in D to "really" extend an existing object, is to wrap it into a new object. And even then, the wrapping is limited, because you can't orthogonally wrap (eg the wrapping linearly stacks, whereas UCFS *could* add two completely independent functionalities). Not to mention issues with code bloat... C++'s namespaces have their flaws, but they *are* scalable in a way D's modules aren't, thanks to Koenig Lookup.
Apr 06 2014
On 4/6/2014 2:00 PM, monarch_dodra wrote:On Sunday, 6 April 2014 at 20:17:09 UTC, Walter Bright wrote:Yes, my mistake.D has closed scopes, and members can be "added" to external classes just fine, using CTFE.You mean UFCS?As in, for example, "front" for arrays? It doesn't work as well as advertised though. The issue is that the added members are only visible if the *called* code knows to import the *caller* code.That's a feature of a modular system, not a bug. D does not have a global name space, on purpose.This breaks as soon as you leave your own internal ecosystem. //---- import a; struct S //Some object { } //Extend to make it a range. bool empty(S); int front(S); void popFront(S); //Try it. void main() { S s; foreach(e; s) //Error: invalid foreach aggregate s writeln(s); s.array(); //Error: template std.range.take cannot... a.foo(s); //Error: no property 'popFront' for type 'S' } //---- module a; void foo(T)(T t) { t.popFront(); } //---- Well that horribly fails.That's based on a misunderstanding of how scoped lookup works in D, and how to use it properly. In the particular instance above, there is simply no reason to not put front() as a member of S, since they are in the same module.Because when calling a template, you are only importing the passed argument, but not his ecosystem with it. The only way in D to "really" extend an existing object, is to wrap it into a new object. And even then, the wrapping is limited, because you can't orthogonally wrap (eg the wrapping linearly stacks, whereas UCFS *could* add two completely independent functionalities). Not to mention issues with code bloat...You're right in that if you try to do things the C++ way in D, things won't work out so well. D can do all these things, but they are done in a different way - a way that is much more robust. The fault in the C++ method of extending namespaces is that two independently developed modules had better not extend the same namespace with the same names. You will not necessarily get a compiler error from violating this - code may just wind up calling the wrong overload. I.e. it does not scale.C++'s namespaces have their flaws, but they *are* scalable in a way D's modules aren't, thanks to Koenig Lookup.I've never seen anyone defend Koenig lookup as anything but a hack before :-)
Apr 06 2014
On 2014-04-06 19:39:31 +0000, "Ola Fosheim Grøstad" <ola.fosheim.grostad+dlang gmail.com> said:Unfortunately that seems to be years into the future? Although clang has begun implementing something: http://clang.llvm.org/docs/Modules.html I've got at feeling that if clang gets something working it will become a de-facto standard due to demand.Modules are already in use on OS X for some system frameworks. It can result in slightly improved compile times. It has been enabled by default for new Xcode projects for some time. With modules enabled, clang interpret #includes as module imports for system frameworks having a module map. It's so transparent you probably won't notice anything has changed. The only thing that really changes with modules is you don't have access to symbols you don't have imported yourself. D already works like that. I think D can ignore those modules, just like it ignores header files. -- Michel Fortin michel.fortin michelf.ca http://michelf.ca
Apr 06 2014
On Monday, 7 April 2014 at 01:35:37 UTC, Michel Fortin wrote:Modules are already in use on OS X for some system frameworks. It can result in slightly improved compile times. It has been enabled by default for new Xcode projects for some time.Thanks for sharing, I wasn't aware of that. That means that clang will make this a priority. But I guess clang is a long way from not having end users write their own header files still.
Apr 07 2014
On Monday, 7 April 2014 at 08:06:11 UTC, Ola Fosheim Grøstad wrote:On Monday, 7 April 2014 at 01:35:37 UTC, Michel Fortin wrote:clang developers are the ones driving the ISO C++ Modules working group, so whatever clang does, it will eventually be the standard. -- PauloModules are already in use on OS X for some system frameworks. It can result in slightly improved compile times. It has been enabled by default for new Xcode projects for some time.Thanks for sharing, I wasn't aware of that. That means that clang will make this a priority. But I guess clang is a long way from not having end users write their own header files still.
Apr 07 2014
Michel Fortin:Here's a suggestion: namespace A.B { // can create two levels at once, yeah! void foo(); void bar(); } namespace C { void foo(); } Make those C++ declarations, it does not look too foreign anymore: extern (C++) namespace A.B { void foo(); void bar(); } extern (C++) namespace C { void foo(); }I suggest to keep the access to C++ namespaces as a feature for interoperability only, and to have no namespaces in D. Bye, bearophile
Apr 05 2014
On 2014-04-05 20:47:32 +0000, Walter Bright <newshound2 digitalmars.com> said:Yes, this seems to be a fatal flaw. Another design that has evolved from these discussions and my discussions with Andrei on it: extern (C++, namespace = A.B) { void foo(); void bar(); } extern (C++, namespace = C) void foo(); bar(); // works A.B.bar(); // works foo(); // error: ambiguous C.foo(); // works alias C.foo foo; foo(); // works, calling C.foo()What if you also have a C++ foo at global scope? module cpptest; extern (C++) void foo(); extern (C++, namespace = A) void foo(); foo(); // ambiguous A.foo(); // works .foo(); // works? cpptest.foo(); // works? Does these two last lines make sense? -- Michel Fortin michel.fortin michelf.ca http://michelf.ca
Apr 05 2014
On 4/5/2014 6:26 PM, Michel Fortin wrote:What if you also have a C++ foo at global scope?It'll work exactly the same as import does.module cpptest; extern (C++) void foo(); extern (C++, namespace = A) void foo(); foo(); // ambiguous A.foo(); // works .foo(); // works?Yes.cpptest.foo(); // works?Yes.Does these two last lines make sense?Just as much sense as: module bar; void foo(); .foo(); // works bar.foo(); // works Namespace lookup rules would be exactly the same as for imports and mixin templates.
Apr 05 2014
On Sunday, 6 April 2014 at 02:33:38 UTC, Walter Bright wrote:On 4/5/2014 6:26 PM, Michel Fortin wrote:My main reservation against the new suggestion is that one would be forced to open a new nested namespace even when it's detrimental, because in some cases the namespace structure is already reflected in the filesystem(just like for D:s module system). I can't assess how widespread this is globally, but at least some high-quality projects already have guidelines to use file/namespace mappings. A random example from boost: boost::asio::ip::multicast boost/asio/ip/multicast.hpp One can of course workaround this issue with an extra alias for every imported symbol, or use compile-time reflection to auto-generate all alias statements... (or heaven forbid, put entire boost in one file ;)) I assume the "namespace = xxx" syntax is some sort of named parameter, would it be possible to add another similar param, which only changes mangling and doesn't actually create a new scope?What if you also have a C++ foo at global scope?It'll work exactly the same as import does.module cpptest; extern (C++) void foo(); extern (C++, namespace = A) void foo(); foo(); // ambiguous A.foo(); // works .foo(); // works?Yes.cpptest.foo(); // works?Yes.Does these two last lines make sense?Just as much sense as: module bar; void foo(); .foo(); // works bar.foo(); // works Namespace lookup rules would be exactly the same as for imports and mixin templates.
Apr 06 2014
On Sat, 05 Apr 2014 13:47:32 -0700, Walter Bright <newshound2 digitalmars.com> wrote:On 4/2/2014 3:07 PM, Walter Bright wrote:This seems like a reasonable way to interop with C++ namespace in a D way. I also think that it is something that we should do ASAP. I know that for Aurora, I will not be able to add complete DirectX support until the C++ namespace interop problem is solved. Specifically because the highly optimized DirectXMath functions are inside a namespace. I do not consider pre-mangling a solution, it's a hack for something that is quite common in C++, and it's fragile. -- Adam Wilson GitHub/IRC: LightBender Aurora Project CoordinatorOne downside of this proposal is that if we ever (perish the thought!) attempted to interface to C++ templates, this design would preclude that.Yes, this seems to be a fatal flaw. Another design that has evolved from these discussions and my discussions with Andrei on it: extern (C++, namespace = A.B) { void foo(); void bar(); } extern (C++, namespace = C) void foo(); bar(); // works A.B.bar(); // works foo(); // error: ambiguous C.foo(); // works alias C.foo foo; foo(); // works, calling C.foo() I really think the namespace semantics should be attached to the extern(C++) rather than be a separate pragma. Having the namespace= thing means that namespace isn't a keyword, and provides a general mechanism where we can add language specific information as necessary.
Apr 07 2014
On Saturday, 5 April 2014 at 20:47:29 UTC, Walter Bright wrote:On 4/2/2014 3:07 PM, Walter Bright wrote:I actually like this idea the most. It is clean, and easy to understand.One downside of this proposal is that if we ever (perish the thought!) attempted to interface to C++ templates, this design would preclude that.Yes, this seems to be a fatal flaw. Another design that has evolved from these discussions and my discussions with Andrei on it: extern (C++, namespace = A.B) { void foo(); void bar(); } extern (C++, namespace = C) void foo(); bar(); // works A.B.bar(); // works foo(); // error: ambiguous C.foo(); // works alias C.foo foo; foo(); // works, calling C.foo() I really think the namespace semantics should be attached to the extern(C++) rather than be a separate pragma. Having the namespace= thing means that namespace isn't a keyword, and provides a general mechanism where we can add language specific information as necessary.
Apr 07 2014