www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - DIP61: redone to do extern(C++,N) syntax

reply Walter Bright <newshound2 digitalmars.com> writes:
http://wiki.dlang.org/DIP61
Apr 27 2014
next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 27 April 2014 at 19:54:50 UTC, Walter Bright wrote:
 http://wiki.dlang.org/DIP61

Sounds awesome.
Apr 27 2014
prev sibling next sibling parent reply "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Sunday, 27 April 2014 at 19:54:50 UTC, Walter Bright wrote:
 http://wiki.dlang.org/DIP61

Without aliasing and with a unified scope operator you will get name clashes between D and C++. You should address why this is not an issue (e.g. practical and not tedious).
Apr 27 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/27/2014 1:44 PM, "Ola Fosheim Grøstad" 
<ola.fosheim.grostad+dlang gmail.com>" wrote:
 On Sunday, 27 April 2014 at 19:54:50 UTC, Walter Bright wrote:
 http://wiki.dlang.org/DIP61

Without aliasing and with a unified scope operator you will get name clashes between D and C++. You should address why this is not an issue (e.g. practical and not tedious).

Example of what you mean, please.
Apr 27 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/27/2014 7:53 PM, "Ola Fosheim Grøstad" 
<ola.fosheim.grostad+dlang gmail.com>" wrote:
 On Sunday, 27 April 2014 at 20:53:31 UTC, Walter Bright wrote:
 Example of what you mean, please.

If the c++ library is "std::" and then later either D or C++ is expanded with a name clash, and the externs are auto generated, e.g. "std.something" appears on both sides, what happens then when you recompile you app?

I don't know what you mean. D has an excellent system for resolving names that appear in multiple scopes.
Apr 27 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/27/2014 11:01 PM, Walter Bright wrote:
 On 4/27/2014 7:53 PM, "Ola Fosheim Grøstad"
 <ola.fosheim.grostad+dlang gmail.com>" wrote:
 On Sunday, 27 April 2014 at 20:53:31 UTC, Walter Bright wrote:
 Example of what you mean, please.

If the c++ library is "std::" and then later either D or C++ is expanded with a name clash, and the externs are auto generated, e.g. "std.something" appears on both sides, what happens then when you recompile you app?

I don't know what you mean. D has an excellent system for resolving names that appear in multiple scopes.

What I mean is I need a specific code example of what you're talking about, as I cannot deduce it from your statement.
Apr 27 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/27/2014 11:30 PM, "Ola Fosheim Grøstad" 
<ola.fosheim.grostad+dlang gmail.com>" wrote:
 On Monday, 28 April 2014 at 06:18:01 UTC, Walter Bright wrote:
 What I mean is I need a specific code example of what you're talking about, as
 I cannot deduce it from your statement.

I assume that the type is structural for the extern so that won't be a problem,

I have no idea what a type being "structural for the extern" means.
 but if std:: is extern in library1 and library2 and I also later need a D
 identifier std.something, will I then have to write:

 library1.cppbinding.std.something
 library2.std.something

 instead of std::something?

1. in D you will never write std::something 2. D can access a function foo without qualification in multiple imports, as long as the overloads do not intersect 3. Otherwise, you'll need to qualify to say which one you meant 4. DIP61 does not change name lookup rules 5. If you have an M::foo defined in one C++ library, and M::foo defined in another C++ library, then your program will fail to link, whether you call those libraries from D or C++ code. D does not fix C++'s One Definition Rule.
Apr 27 2014
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/28/2014 12:45 AM, Temtaime wrote:
 I think he meant next:

 A.d:
 void foo();

 A.cpp:
 namespace A { void foo(); }

 And now we has:

 exnern(C++, A) void foo();
 import A;

Error, A is defined twice.
Apr 28 2014
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/28/2014 4:29 AM, "Ola Fosheim Grøstad" 
<ola.fosheim.grostad+dlang gmail.com>" wrote:
 This is close. Forgive inaccurate syntax, but I see at least these issues that
 will make namespaces/module-system broken in terms of maintenance:

 YEAR 2014:

 framework1.d:
 extern (C++, std){ void something(); }

 framework2.d:
 extern (C++,std){void something(); void anything();}

 application.d:
 import framework1;
 import framework2;
 … std.something(); // is this ok, because the extern signatures match?

No. Even though they are the same function as far as the signatures are concerned, they are different functions as far as the D type system is concerned, and hence the call is ambiguous. You'll have to qualify by framework1.std.something() or framework2.std.something().
 std.d is updated:
 void something(){}
 void coolstuff(){}

 application.d is updated to use the new coolstuff():
 import framework1;
 import framework2;
 import.std();
 … std.something(); // namespace encapsulation broken or fail?
 … std.coolstuff();

No problem, std.d overrides because it is imported directly and so std is in the current scope. The current scope overrides imported scopes.
 application.d is corrected to (or using some other resolution):
 import framework1;
 import framework2;
 import.std();
 … framework2.std.something();
 … std.coolstuff();

Again, no problem.
 YEAR 2016:

 framework2.d is modified:
 extern (C++,std){ void anything(); }

 application.d is recompiled unmodified:
 import framework1;
 import framework2;
 import.std();
   // fails even though the signature is still in framework1
 … framework2.std.something();

Still no problem. Qualifying it with framework2 says which one you want.
 … std.coolstuff();

Remember std is a symbol in the current scope.
 Right, but I want to be sure that the type-system sees all externs with the
same
 signature as the same type.

Remember, a C++ signature is the same as its type in C++, but that is not true of D.
 I also am not sure how the "closing of namespaces"
 will work if you have multiple frameworks that independently specify their own
 C++ bindings to the same library.

D will regard those namespaces as completely separate and distinct scopes. The fact that C++ symbols in those separate scopes will mangle to the same symbol is up to the programmer to deal with - the same as with extern(C) symbols.
 The sole purpose of namespace/modules is to have clean separation between
 frameworks and support evolutionary development. I am not convinced that this
 property is not broken with the proposed change.

 To get around this you will have to remove the "closing of namespaces"
 restriction and add a root "cpp" so that all cpp namespaces get:
 cpp.std.something() etc…

I don't think there's anything needed to be gotten around here.
Apr 28 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/28/2014 4:30 PM, "Ola Fosheim Grøstad" 
<ola.fosheim.grostad+dlang gmail.com>" wrote:
 On Monday, 28 April 2014 at 19:32:10 UTC, Walter Bright wrote:
 On 4/28/2014 4:29 AM, "Ola Fosheim Grøstad"
 <ola.fosheim.grostad+dlang gmail.com>" wrote:
 No. Even though they are the same function as far as the signatures are
 concerned, they are different functions as far as the D type system is
 concerned, and hence the call is ambiguous. You'll have to qualify by
 framework1.std.something() or framework2.std.something().

So you have to choose between framework1 and 2's version if std::string when building your own class, an then cast back and forth between the different framework bindings even though the actual type is the same? Isn't that tedious?

First off, I expect "std" to be put in core.stdcpp.std, and then imported. So this issue would only happen if 3rd party A and 4th party B each imported 5th party C. Yeah, it'll happen, and it'll still work, as the import system regards the same file as being the same import regardless of the import path used to get to it. The SAME issue exists with D imports. DIP61 does not change this.
 But I think that it is a problem that std.something is silently rebound to a
 different function.

It's no different than if you have: A::foo() in one framework, and a different: A::foo() in another framework. It won't work in C++, either.
 The problem is that you are forced to qualify the D-binding rather than the
path
 of the cpp function. This will only work out ok if different framework authors
 cooperate.

Not correct. This is not a problem.
 Remember, a C++ signature is the same as its type in C++, but that is not true
 of D.

And that makes it tedious to interact with C++?

I don't see how it makes it any more tedious than dealing with the ODR rule in C++ anyway.
Apr 28 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/28/2014 11:06 PM, "Ola Fosheim Grøstad" 
<ola.fosheim.grostad+dlang gmail.com>" wrote:
 On Monday, 28 April 2014 at 23:57:36 UTC, Walter Bright wrote:
 First off, I expect "std" to be put in core.stdcpp.std, and then imported. So
 this issue would only happen if 3rd party A and 4th party B each imported 5th
 party C. Yeah, it'll happen, and it'll still work, as the import system
 regards the same file as being the same import regardless of the import path
 used to get to it.

No, it'll happen if they use the same vector library an #include the same "vector3D" and independently specify their own binding? But if they cooperate and use the same binding, then you are ok? That makes no sense.

I simply don't know what you're talking about when you use the word "binding".
 It's no different than if you have:

    A::foo()

 in one framework, and a different:

    A::foo()

 in another framework. It won't work in C++, either.

That is only true if you mangle D modules and C++ namespaces the same way.

C++ identifiers do not get the module name mangled in.
 You should be able to have A.foo and A::foo. It makes no sense to conflate the
paths
 if they mangle differently.

There is no A::foo in D.
 The problem is that you are forced to qualify the D-binding rather than the
path
 of the cpp function. This will only work out ok if different framework authors
 cooperate.

Not correct. This is not a problem.

I can mix two independent cpp bindings without casting?

Casting has nothing to do with symbol lookup.
 Why not? It only applies to the translation unit. I see no relationship.

I'm sorry, I do not understand what your mental model of how this works is. Perhaps if you wrote your questions in terms of D code examples, I can answer them.
Apr 28 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/29/2014 12:10 AM, "Ola Fosheim Grøstad" 
<ola.fosheim.grostad+dlang gmail.com>" wrote:
 On Tuesday, 29 April 2014 at 06:50:19 UTC, Walter Bright wrote:
 No, it'll happen if they use the same vector library an #include the same
 "vector3D" and independently specify their own binding? But if they cooperate
 and use the same binding, then you are ok? That makes no sense.

I simply don't know what you're talking about when you use the word "binding".

You bind the C++ extern to a D path, and as a result you get 2 types because you have 2 paths rather than one. (according to what you have said) If they mangle to the same name then I want them to be the same type.

The namespace contributes to the mangling of C++ symbols, but has no contribution to its type.
 As a result I am better off when using pure C++ frameworks and creating my own
D
 layer than when I am using 2 mixed D/C++ frameworks that have been developed
 independently.

 C++ identifiers do not get the module name mangled in.

An therefore they should be seen as the same type!

The type is not a scope.
Apr 29 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
Basically, Ola, if you could write a piece of sample D code that you feel will 
not work, please do so.
Apr 29 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/29/2014 2:01 AM, "Ola Fosheim Grøstad" 
<ola.fosheim.grostad+dlang gmail.com>" wrote:
 framework1.d:
 extern(C++,veclib){ struct … vec4 …; }
 extern(C++,physics){ vec4 f(vec4 …) … }

 framework2.d:
 extern(C++,veclib){ struct … vec4 …; }
 extern(C++,graphics){ void g(vec4 …) … }

 application1.d:
 import framework1;
 import framework2;

 graphics.g( physics.f(…) ); // you said this would not work?

That won't work because framework1.veclib.vec4 is not the same as framework2.veclib.vec4, as far as D's symbol lookup is concerned.
 -----
 myframework.d
 extern(C++,veclib){ struct … vec4 …; }
 extern(C++,physics){ vec4 f(vec4 …) … }
 extern(C++,graphics){ void g(vec4 …) … }

 application2.d
 import myframework;

 graphics.g( physics.f(…) ); // but now it works?

Yes, because now there is only one myframework.veclib.vec4. I'd do your example as: vec.d: extern(C++,veclib){ struct … vec4 …; } framework1.d: import vec; extern(C++,physics){ vec4 f(vec4 …) … } framework2.d: import vec; extern(C++,graphics){ void g(vec4 …) … } application1.d: import framework1; import framework2; graphics.g( physics.f(…) ); // works
Apr 29 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/29/2014 1:23 PM, "Ola Fosheim Grøstad" 
<ola.fosheim.grostad+dlang gmail.com>" wrote:
 On Tuesday, 29 April 2014 at 19:48:36 UTC, Walter Bright wrote:
 I'd do your example as:

 vec.d:
 extern(C++,veclib){ struct … vec4 …; }

 framework1.d:
 import vec;
 extern(C++,physics){ vec4 f(vec4 …) … }

 framework2.d:
 import vec;
 extern(C++,graphics){ void g(vec4 …) … }

Yes, but that requires the authors of framework1 and framework2 to cooperate.

Not really. It is reasonable to expect that when Framework1 and Framework2 each import 4th party Vec, that they do it with an import rather than inlining Vec's declarations.
 Which is why you with this DIP will end up with people being better off by
using
 pure C++ rather than mixed D/C++ from different sources.

 With "graphics::g(physics::f(…))" this would not have been an issue.

Having an alternative lookup method is a large increase in language complexity.
Apr 29 2014
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/29/2014 1:33 PM, Walter Bright wrote:
 On 4/29/2014 1:23 PM, "Ola Fosheim Grøstad"
 With "graphics::g(physics::f(…))" this would not have been an issue.


It does occur to me that two C++ symbols in the same namespace may be regarded as the same by the lookup code. That may be a reasonable enhancement request.
Apr 29 2014
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/28/2014 1:31 AM, "Ola Fosheim Grøstad" 
<ola.fosheim.grostad+dlang gmail.com>" wrote:
 So recompiling with updated libraries may cause failure?

No more than if you violate the ODR in C++, or if you do this entirely in D. Ambiguities for the latter will cause compile time errors (which is a feature, not a bug).
Apr 28 2014
prev sibling next sibling parent reply Caligo via Digitalmars-d <digitalmars-d puremagic.com> writes:
--001a11c2c1d2eccef904f80d6bde
Content-Type: text/plain; charset=UTF-8

On Sun, Apr 27, 2014 at 2:54 PM, Walter Bright via Digitalmars-d <
digitalmars-d puremagic.com> wrote:

 http://wiki.dlang.org/DIP61

What happens if you try to interface with two different C++ libraries that use the same exact namespaces? --001a11c2c1d2eccef904f80d6bde Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">On S= un, Apr 27, 2014 at 2:54 PM, Walter Bright via Digitalmars-d <span dir=3D"l= tr">&lt;<a href=3D"mailto:digitalmars-d puremagic.com" target=3D"_blank">di= gitalmars-d puremagic.com</a>&gt;</span> wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"><a href=3D"http://wiki.dlang.org/DIP61" targ= et=3D"_blank">http://wiki.dlang.org/DIP61</a><br> </blockquote></div><br></div><div class=3D"gmail_extra">What happens if you= try to interface with two different C++ libraries that use the same exact = namespaces?</div></div> --001a11c2c1d2eccef904f80d6bde--
Apr 27 2014
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/27/2014 3:07 PM, Caligo via Digitalmars-d wrote:
 On Sun, Apr 27, 2014 at 2:54 PM, Walter Bright via Digitalmars-d
 <digitalmars-d puremagic.com <mailto:digitalmars-d puremagic.com>> wrote:

     http://wiki.dlang.org/DIP61


 What happens if you try to interface with two different C++ libraries that use
 the same exact namespaces?

If any of the names mangle to the same string, you'll get errors from the linker, just as you would if referencing those libraries from C++.
Apr 27 2014
prev sibling next sibling parent reply "Brian Schott" <briancschott gmail.com> writes:
On Sunday, 27 April 2014 at 19:54:50 UTC, Walter Bright wrote:
 http://wiki.dlang.org/DIP61

This is the new grammar? LinkageAttribute: 'extern' '(' identifier '++'? (',' identifier)? ')'
Apr 27 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/27/2014 5:58 PM, Brian Schott wrote:
 On Sunday, 27 April 2014 at 19:54:50 UTC, Walter Bright wrote:
 http://wiki.dlang.org/DIP61

This is the new grammar? LinkageAttribute: 'extern' '(' identifier '++'? (',' identifier)? ')'

You can also have N.M
Apr 27 2014
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/29/2014 4:08 PM, Brian Schott wrote:
 I've updated the DIP page to include documentation of the change to the
language
 grammar.

thanks!
Apr 29 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Sunday, 27 April 2014 at 20:53:31 UTC, Walter Bright wrote:
 Example of what you mean, please.

If the c++ library is "std::" and then later either D or C++ is expanded with a name clash, and the externs are auto generated, e.g. "std.something" appears on both sides, what happens then when you recompile you app?
Apr 27 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Monday, 28 April 2014 at 06:18:01 UTC, Walter Bright wrote:
 What I mean is I need a specific code example of what you're 
 talking about, as I cannot deduce it from your statement.

I assume that the type is structural for the extern so that won't be a problem, but if std:: is extern in library1 and library2 and I also later need a D identifier std.something, will I then have to write: library1.cppbinding.std.something library2.std.something instead of std::something?
Apr 27 2014
prev sibling next sibling parent reply "Sergei Nosov" <sergei.nosov gmail.com> writes:
On Sunday, 27 April 2014 at 19:54:50 UTC, Walter Bright wrote:
 http://wiki.dlang.org/DIP61

Quote:
 Unlike C++, namespaces in D will be 'closed' meaning that new 
 declarations cannot be inserted into a namespace after the 
 closing }. C++ Argument Dependent Lookup (aka "Koenig Lookup") 
 will not be supported.

Do I understand it correctly, that if I have namespace members defined in different files, like // a.cpp namespace ns { int foo(); } // b.cpp namespace ns { int bar(); } I have the only option to put those in a single D file, like // c.d extern (C++, ns) { int foo(); int bar(); } ? And the only way it's more flexible than the hypothetical extern(C++) module ns; is that you can put several namespaces to a single file?
Apr 28 2014
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/28/2014 12:18 AM, Sergei Nosov wrote:
 On Sunday, 27 April 2014 at 19:54:50 UTC, Walter Bright wrote:
 http://wiki.dlang.org/DIP61

Quote:
 Unlike C++, namespaces in D will be 'closed' meaning that new declarations
 cannot be inserted into a namespace after the closing }. C++ Argument
 Dependent Lookup (aka "Koenig Lookup") will not be supported.

Do I understand it correctly, that if I have namespace members defined in different files, like // a.cpp namespace ns { int foo(); } // b.cpp namespace ns { int bar(); } I have the only option to put those in a single D file, like // c.d extern (C++, ns) { int foo(); int bar(); } ?

That is incorrect. As far as D is concerned, a.ns and b.ns are separate and distinct declarations, even if C++ members of those scopes may mangle to the same name.
 And the only way it's more flexible than the hypothetical extern(C++) module
ns;
 is that you can put several namespaces to a single file?

People who write namespaces in C++ do not pay much attention to what .h files they are in. People writing D imports for such C++ code should not have to re-engineer the layout of the files.
Apr 28 2014
prev sibling next sibling parent "Temtaime" <temtaime gmail.com> writes:
I think he meant next:

A.d:
void foo();

A.cpp:
namespace A { void foo(); }

And now we has:

exnern(C++, A) void foo();
import A;

void main() {
A.foo(); // which foo will be called ? how to call d version or 
c++ ?
}

There's no linker problem because D and C++ has different name 
mangling.
Apr 28 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Monday, 28 April 2014 at 06:47:08 UTC, Walter Bright wrote:
 I have no idea what a type being "structural for the extern" 
 means.

"structural" is the wrong word. I meant that if two D frameworks bind the same c++ library you want the two externs to be interchangable in user code. However if D libraries overlaps the identifier path then you run into namespace issues. So the probability of expanding libraries causing issues increase by conflating D and C++ identifier paths.
 1. in D you will never write std::something

Which will cause unecessary naming conflicts.
 2. D can access a function foo without qualification in 
 multiple imports, as long as the overloads do not intersect

 3. Otherwise, you'll need to qualify to say which one you meant

So recompiling with updated libraries may cause failure?
Apr 28 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Monday, 28 April 2014 at 07:45:20 UTC, Temtaime wrote:
 I think he meant next:

 A.d:
 void foo();

 A.cpp:
 namespace A { void foo(); }

 And now we has:

 exnern(C++, A) void foo();
 import A;

 void main() {
 A.foo(); // which foo will be called ? how to call d version or 
 c++ ?
 }

This is close. Forgive inaccurate syntax, but I see at least these issues that will make namespaces/module-system broken in terms of maintenance: YEAR 2014: framework1.d: extern (C++, std){ void something(); } framework2.d: extern (C++,std){void something(); void anything();} application.d: import framework1; import framework2; … std.something(); // is this ok, because the extern signatures match? --------- YEAR 2015: std.d is updated: void something(){} void coolstuff(){} application.d is updated to use the new coolstuff(): import framework1; import framework2; import.std(); … std.something(); // namespace encapsulation broken or fail? … std.coolstuff(); application.d is corrected to (or using some other resolution): import framework1; import framework2; import.std(); … framework2.std.something(); … std.coolstuff(); --- YEAR 2016: framework2.d is modified: extern (C++,std){ void anything(); } application.d is recompiled unmodified: import framework1; import framework2; import.std(); // fails even though the signature is still in framework1 … framework2.std.something(); … std.coolstuff();
 There's no linker problem because D and C++ has different name 
 mangling.

Right, but I want to be sure that the type-system sees all externs with the same signature as the same type. I also am not sure how the "closing of namespaces" will work if you have multiple frameworks that independently specify their own C++ bindings to the same library. The sole purpose of namespace/modules is to have clean separation between frameworks and support evolutionary development. I am not convinced that this property is not broken with the proposed change. To get around this you will have to remove the "closing of namespaces" restriction and add a root "cpp" so that all cpp namespaces get: cpp.std.something() etc…
Apr 28 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
 This is close. Forgive inaccurate syntax, but I see at least these  =

 issues that will make namespaces/module-system broken in terms of  =

 maintenance:

 YEAR 2014:

 framework1.d:
 extern (C++, std){ void something(); }

 framework2.d:
 extern (C++,std){void something(); void anything();}

 application.d:
 import framework1;
 import framework2;
 =E2=80=A6 std.something(); // is this ok, because the extern signature=

Not ok. This is like having 2 definitions for the same function, linker = = will not accept that. -Steve
Apr 28 2014
prev sibling next sibling parent reply Byron <byron.heads gmail.com> writes:
On Sun, 27 Apr 2014 12:54:51 -0700, Walter Bright wrote:

 http://wiki.dlang.org/DIP61

I really like this. I think it is clean simple and a better approach then adding the namespace keyword. Plus when people come to D from C++ they wont misuse namespace. Since D has awesome module aliasing we don't have to worry to much about module/namespace conflicts. Though it would be interesting to alias the extern directly (if we cant already). alias lib1 = extern(C++, company.lib1) { .... }; My only concern is when libraries have extension libraries that add to the main libraries namespace. ie: big_library_everyone_loves_to_use.c++ namespace biglib { namespace core { ... } } small_helper_lib_a_few_people_use.c++ namespace biglib { void helper1() ... // I call 50 functions so you dont have to! namespace core() { ... } // I add extra special memory handlers } With the current DIP you have to combine the d/di files to merge the extern namespaces. Makes it hard to maintain these as separate libraries. Specially when your library has a lot of extension libs. Maybe someone can write a cleaver mixin for this problem. Also is there any plans on dealing with newing c++ memory? Having to add factories to all of the c++ libs feels a little goofy, but either way this DIP gets us a lot closer to C++/D bliss!
Apr 28 2014
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/28/2014 6:55 AM, Byron wrote:
 With the current DIP you have to combine the d/di files to merge the
 extern namespaces.

No, you will not have to, for the same reason that all extern(C) declarations don't have to be in the same module.
 Also is there any plans on dealing with newing c++ memory?

AAAAAIIIIIEEEEEEEE!!!
Apr 28 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Monday, 28 April 2014 at 13:47:43 UTC, Steven Schveighoffer 
wrote:
 Not ok. This is like having 2 definitions for the same 
 function, linker will not accept that.

No. It is like having 2 matching type declarations. The implementation is defined in the C++ source code and is represented as one C++ object/lib file to the linker. The linker will happily accept that.
Apr 28 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 28 Apr 2014 10:00:56 -0400, Ola Fosheim Gr=C3=B8stad  =

<ola.fosheim.grostad+dlang gmail.com> wrote:

 On Monday, 28 April 2014 at 13:47:43 UTC, Steven Schveighoffer wrote:
 Not ok. This is like having 2 definitions for the same function, link=


 will not accept that.

No. It is like having 2 matching type declarations. The implementation=

 is defined in the C++ source code and is represented as one C++  =

 object/lib file to the linker. The linker will happily accept that.

Oh sorry, in my head, I was sure they each had implementations ;) Yeah, I think that should work just fine. I see now where your objection is. I think either the rule needs to be = better explained, or that it is incorrect. -Steve
Apr 28 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Monday, 28 April 2014 at 14:08:56 UTC, Steven Schveighoffer 
wrote:
 I see now where your objection is. I think either the rule 
 needs to be better explained, or that it is incorrect.

I think so too, because if my undestanding is correct then it will discourage writing libs in mixed D/C++ and encourage writing libs in pure C++. Basically turning D into an application level language (on the level of Objective-C so to speak)?
Apr 28 2014
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 27 Apr 2014 15:54:51 -0400, Walter Bright  
<newshound2 digitalmars.com> wrote:

 http://wiki.dlang.org/DIP61

I think there is a big problem with name lookup here. Consider this code: module foo; void func() {} module bar; extern(C) func(); module prog; import foo; import bar; void main() { func(); // error foo.func(); // ok bar.func(); // ok, uses C binding (no name mangling) } In this case, even though the C function is not mangled or in any other namespace, the module can be used for unambiguous calling. But in your proposal, the name qualifiers could be either C++ namespaces or D modules. This presents an unnecessary ambiguity. e.g. module foo; void func() {} module bar; extern(C++, foo) void func(); // foo::func in C++ land module prog; import foo; import bar; void main() { func(); // error foo.func(); // ALSO error bar.func(); // Not error, BUT it's actually calling foo::func from C++ land! } I think we cannot change name lookup rules for C++ symbols, because the D module system already owns those. An alternative is that you could create an alternate way to disambiguate. Let's pick a strawman called _cpp, just to illustrate: void main() { func(); // error still foo.func(); // calls D's foo module's func bar.func(); // calls D's bar module's func (defined as foo::func) _cpp.func(); // error, _cpp denotes we are using namespace qualifiers, and there is no global C++ func _cpp.foo.func(); // calls D's bar module's func. bar._cpp.foo.func(); // ditto } Really, _cpp could be anything. But I think hijacking D's module qualifiers does not help. To make things seamless, you could make it ::, but I know many people have objections to that. -Steve
Apr 28 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/28/2014 7:27 AM, Steven Schveighoffer wrote:
 Consider this code:

 module foo;

 void func() {}

 module bar;

 extern(C) func();

 module prog;

 import foo;
 import bar;

 void main()
 {
     func(); // error
     foo.func(); // ok
     bar.func(); // ok, uses C binding (no name mangling)
 }

 In this case, even though the C function is not mangled or in any other
 namespace, the module can be used for unambiguous calling.

Right.
 module foo;

 void func() {}

 module bar;

 extern(C++, foo) void func(); // foo::func in C++ land

 module prog;

 import foo;
 import bar;

 void main()
 {
     func(); // error
     foo.func(); // ALSO error

No, not an error. Why would it be?
     bar.func(); // Not error, BUT it's actually calling foo::func from C++
land!

That's right. Note that foo::func() is not the same as bar.foo.func().
 }

Apr 28 2014
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/28/2014 2:00 PM, Simen Kjærås via Digitalmars-d wrote:
 I believe Steven expects things to work this way:

 module bar;

 extern(C++, foo) void func();


 module prog;

 import bar;

 void main()
 {
     foo.func(); // Calls bar.func (or is that bar.foo.func?)
 }

It would call bar.foo.func(). But your example is different from Steven's.
Apr 28 2014
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/29/2014 01:34 PM, Simen Kjærås via Digitalmars-d wrote:
 Building on this knowledge:

 module foo;

 void func();


 module bar;

 extern(C++, foo) void func();


 module prog;

 import foo;
 import bar;

 void main()
 {
      // Seems like it's ambiguous between foo.func and bar.foo.func.
      foo.func();
 }

It will call foo.func, because the module foo is in scope in module prog and hence hides the namespace foo in module bar. You can already try this today, as the DIP _does not actually introduce any new lookup rules_: module a; void func(){} //--- module bar; mixin template X(){ void func(); } mixin X foo; //--- import foo,bar; void main(){ foo.func(); } In particular, any problems you find with symbol lookup are actually orthogonal to the DIP.
Apr 29 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/29/2014 8:43 AM, Timon Gehr wrote:
 as the DIP _does not actually introduce any new lookup rules_
  [...]
 In particular, any problems you find with symbol lookup are actually orthogonal
 to the DIP.

Yes!
Apr 29 2014
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 4/29/14, 12:49 PM, Walter Bright wrote:
 On 4/29/2014 8:43 AM, Timon Gehr wrote:
 as the DIP _does not actually introduce any new lookup rules_
  [...]
 In particular, any problems you find with symbol lookup are actually
 orthogonal
 to the DIP.

Yes!

This is a biggie. KISS etc. -- Andrei
Apr 29 2014
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/29/2014 02:01 PM, Steven Schveighoffer wrote:
 That is what the DIP says:

 "Declarations in the namespace can be accessed without qualification in
 the enclosing scope if there is no ambiguity. Ambiguity issues can be
 resolved by adding the namespace qualifier"

 Which then  proceeds to show that only the namespace qualifier is needed
 to disambiguate the symbol.

 -Steve

You seem to be missing the only important statement that the DIP makes about symbol disambiguation, that follows straight after those examples: "Name lookup rules are the same as for mixin templates." (Maybe it should say 'named template mixins'.)
Apr 29 2014
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/29/2014 05:52 PM, Steven Schveighoffer wrote:
 I am not familiar with the rules.

 Perhaps you can just outline for me:

 module bar;

 extern(C++, foo) void func();

 module prog;

 import bar;

 void main()
 {
     foo.func(); // works?
 }

 If this works, then we have a problem.

It does work. What happens is analogous to: module bar; void func(){} module prog; import bar; void func(){} void main(){ func(); } I.e. if you add a new symbol to your own module, then this identifier will be hidden, no questions asked. Importing a module adds a new symbol of its name to your module. I'm not sure why you see this as a problem. The name lookup rules are designed such that changes in one module cannot silently change name lookup in _another_ module, but anything may happen to lookup in the same module.
 If it doesn't work, well, then I
 see nobody using this feature (using C++ namespace for disambiguation,
 not the mangling, which is still useful).

 -Steve

The name disambiguation feature fundamentally addresses one simple issue, namely the case when the same name occurs in multiple different namespaces occurring in the same module. (It is trivial to implement in a compiler, if that helps, because there is no new machinery, just share the implementation with named mixin templates.)
Apr 29 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/29/2014 9:13 AM, Steven Schveighoffer wrote:
 But what happens when you add another import that conflicts?

 module foo;

 void func() {}

 module prog; // updated
 import bar;
 import foo;

 void main(){
     foo.func(); // now calls foo.func, and not bar.func as it originally did,
 right?
 }

 So by importing from another module, we have silently and drastically changed
 the behavior. Have I missed something?

 Why is this not a problem?

Because the compiler would now issue an error for that, it's its anti-hijacking feature. Try it and see!
Apr 29 2014
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/29/2014 10:49 PM, Steven Schveighoffer wrote:
 On Tue, 29 Apr 2014 16:00:43 -0400, Steven Schveighoffer
 <schveiguy yahoo.com> wrote:

 On Tue, 29 Apr 2014 15:52:01 -0400, Walter Bright
 <newshound2 digitalmars.com> wrote:

 Because the compiler would now issue an error for that, it's its
 anti-hijacking feature.

 Try it and see!

I agree! that was my central point, which Timon seemed to be arguing against :)

And in fact, so were you! ... This is EXACTLY the same code that you said would now be an error above!

Maybe he didn't notice that you changed the 'main' function relative to my post. If you don't mention 'foo' explicitly, then obviously it cannot be hidden by the import and the code is in error.
 I think you guys  need to reexamine this,

Not me. I typically test my claims even if I am sure, if only to file bug reports.
 and choose one way or another.
 At this point, I have no clue as to how it's supposed to work.

Obviously you did not actually try. :P Again, to make it really easy for you to test the behaviour: module foo; import std.stdio; int func(){ writeln("hello from foo!"); return 1; } //--- module bar; import std.stdio; mixin template X(){ int func(){ writeln("hello from bar!"); return 2; } } mixin X foo; //--- module prog; void main(){ void onlybar(){ import bar; auto r=foo.func(); // hello from bar! assert(r==2); // pass! } void fooandbar(){ import bar,foo; auto r=foo.func(); // hello from foo! assert(r==1); // pass! } onlybar(); fooandbar(); } http://dlang.org/download.html $ dmd prog foo bar && ./prog hello from bar! hello from foo! This is because the import of module 'foo' hides the namespace 'foo' imported from 'bar' in the scope of 'fooandbar'. It is not 'func' that is being hidden, but 'foo'.
Apr 29 2014
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/30/2014 02:41 AM, Steven Schveighoffer wrote:
 On Tue, 29 Apr 2014 17:38:07 -0400, Timon Gehr <timon.gehr gmx.ch> wrote:
 ...
 Maybe he didn't notice that you changed the 'main' function relative
 to my post. If you don't mention 'foo' explicitly, then obviously it
 cannot be hidden by the import and the code is in error.

I never changed the code. It always was foo.func(). That was my point. ...

(What I mean is that in the post you were answering, main just contained 'foo'.)
 I think you guys  need to reexamine this,

Not me. I typically test my claims even if I am sure, if only to file bug reports.

Your view has been consistent. I think it defeats the purpose of having namespaces to disambiguate calls, since the disambiguation itself conflicts with modules. If foo.func means one thing today and another thing tomorrow, based on an import, I think the feature is flawed. Template namespaces are just as flawed.
 and choose one way or another.
 At this point, I have no clue as to how it's supposed to work.

Obviously you did not actually try. :P

No, I get what you are saying. The above statement is because I'm getting conflicting reports from Walter. ...

Ok, apologies.
 ...

 module foo;
 import std.stdio;

 int func(){ writeln("hello from foo!"); return 1; }

 //---

 module bar;
 import std.stdio;

 mixin template X(){
      int func(){ writeln("hello from bar!"); return 2; }
 }
 mixin X foo;

 //---

 module prog;

 void main(){
      void onlybar(){
          import bar;
          auto r=foo.func(); // hello from bar!
          assert(r==2); // pass!
      }
      void fooandbar(){
          import bar,foo;
          auto r=foo.func(); // hello from foo!
          assert(r==1); // pass!
      }
      onlybar();
      fooandbar();
 }

Wouldn't a similar test be to create a struct for a namespace? ...

Yes, and this behaves the same in this specific case.
 The confusing issue here to C++ programmers is, when I specify x::y::z,
 it means z in namespace x::y, regardless of where it was imported. If in
 D we say you can access this via x.y.z, they are going to think they can
 always type that. To have it so easily break is not a good thing.
 ...

If this is a problem, I guess the most obvious alternatives are to: 1. Get rid of namespace scopes. Require workarounds in the case of conflicting definitions in different namespaces in the same file. (Eg. use a mixin template.) I'd presume this would not happen often. 2. Give the global C++ namespace a distinctive name and put all other C++ namespaces below it. This way fully qualified name lookup will be reliable.
 This is because the import of module 'foo' hides the namespace 'foo'
 imported from 'bar' in the scope of 'fooandbar'. It is not 'func' that
 is being hidden, but 'foo'.

In fact, it's the entire foo namespace. ...

Yes, but this is visible in the file that is being changed.
 So basically any namespace that matches the root phobos import path will
 cause conflicts. You don't suppose any C++ code uses that do you? ;)

How many C++ standard headers contain conflicting symbol names in different namespaces? If the namespace symbol really needs to be addressable, there could be an alias. eg. alias cpp=std;
Apr 30 2014
parent Walter Bright <newshound2 digitalmars.com> writes:
On 5/2/2014 12:34 AM, "Ola Fosheim Grøstad" 
<ola.fosheim.grostad+dlang gmail.com>" wrote:
 The implications with this DIP is that all library authors will have to follow
a
 convention of having all C++ dependencies in a module named "cpp" in order to
 have a "fake" way of specifying fully qualified C++ names.

Not at all, any more than you have to do that for C names.
 This is not elegant. It is a hack.

C++ is not elegant, and interfacing to it will necessarily pick up some of that.
May 02 2014
prev sibling next sibling parent Byron <byron.heads gmail.com> writes:
On Mon, 28 Apr 2014 10:27:19 -0400, Steven Schveighoffer wrote:

 On Sun, 27 Apr 2014 15:54:51 -0400, Walter Bright
 <newshound2 digitalmars.com> wrote:
 
 http://wiki.dlang.org/DIP61

I think there is a big problem with name lookup here. Consider this code: module foo; void func() {} module bar; extern(C) func(); module prog; import foo; import bar; void main() { func(); // error foo.func(); // ok bar.func(); // ok, uses C binding (no name mangling) } In this case, even though the C function is not mangled or in any other namespace, the module can be used for unambiguous calling. But in your proposal, the name qualifiers could be either C++ namespaces or D modules. This presents an unnecessary ambiguity. e.g. module foo; void func() {} module bar; extern(C++, foo) void func(); // foo::func in C++ land module prog; import foo; import bar; void main() { func(); // error foo.func(); // ALSO error bar.func(); // Not error, BUT it's actually calling foo::func from C++ land! } I think we cannot change name lookup rules for C++ symbols, because the D module system already owns those. An alternative is that you could create an alternate way to disambiguate. Let's pick a strawman called _cpp, just to illustrate: void main() { func(); // error still foo.func(); // calls D's foo module's func bar.func(); // calls D's bar module's func (defined as foo::func) _cpp.func(); // error, _cpp denotes we are using namespace qualifiers, and there is no global C++ func _cpp.foo.func(); // calls D's bar module's func. bar._cpp.foo.func(); // ditto } Really, _cpp could be anything. But I think hijacking D's module qualifiers does not help. To make things seamless, you could make it ::, but I know many people have objections to that. -Steve

why not import _cpp = bar; ?
Apr 28 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 28 Apr 2014 10:37:36 -0400, Byron <byron.heads gmail.com> wrote:

 why not  import _cpp = bar;   ?

That doesn't help. foo.func() is still ambiguous. With this proposal, you have hijacked the meaning of namespace lookup. When I say x.y.z, it doesn't just mean look for symbol z in module x/y.d, it can also mean to look for symbol z in C++ namespace x::y. This was not the case with C binding, which continued to use D modules for symbol lookup. Consider that a boatload of C++ code is named std::something. Now, std.string has an ambiguous meaning wherever it is used! -Steve
Apr 28 2014
prev sibling next sibling parent reply Byron <byron.heads gmail.com> writes:
On Sun, 27 Apr 2014 12:54:51 -0700, Walter Bright wrote:

 http://wiki.dlang.org/DIP61

Would nesting imported namespaces work? lib/package.d public export(C++, a) { public import lib.b; } lib/b.d export(C++, b) { void foo(); } main.d import lib; a.b.foo();
Apr 28 2014
next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 28 Apr 2014 10:46:33 -0400, Byron <byron.heads gmail.com> wrote:

 On Sun, 27 Apr 2014 12:54:51 -0700, Walter Bright wrote:

 http://wiki.dlang.org/DIP61

Would nesting imported namespaces work? lib/package.d public export(C++, a) { public import lib.b; } lib/b.d export(C++, b) { void foo(); } main.d import lib; a.b.foo();

Most definitely no. When the compiler builds b.d, he has no idea it's imported from inside another namespace! We don't want #include-style issues. -Steve
Apr 28 2014
prev sibling next sibling parent Byron <byron.heads gmail.com> writes:
On Mon, 28 Apr 2014 10:56:24 -0400, Steven Schveighoffer wrote:

 
 Most definitely no. When the compiler builds b.d, he has no idea it's
 imported from inside another namespace! We don't want #include-style
 issues.
 
 -Steve

So we would have to include the entire namespace in a single d file or is this okay: a/package.d extern(C++, a) {} public import a.b; a/b.d extern(C++, a.b) {}
Apr 28 2014
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 28 Apr 2014 11:05:25 -0400, Byron <byron.heads gmail.com> wrote:

 On Mon, 28 Apr 2014 10:56:24 -0400, Steven Schveighoffer wrote:

 Most definitely no. When the compiler builds b.d, he has no idea it's
 imported from inside another namespace! We don't want #include-style
 issues.

 -Steve

So we would have to include the entire namespace in a single d file or is this okay: a/package.d extern(C++, a) {} public import a.b; a/b.d extern(C++, a.b) {}

Yes, that is fine. You could also nest within the same file. But not via an import. In D, it's important that imports are context-free, it doesn't matter where or when you import them. This eliminates all sorts of problems that #include has. -Steve
Apr 28 2014
prev sibling next sibling parent Byron <byron.heads gmail.com> writes:
On Mon, 28 Apr 2014 10:45:14 -0400, Steven Schveighoffer wrote:

 On Mon, 28 Apr 2014 10:37:36 -0400, Byron <byron.heads gmail.com> wrote:
 
 
 why not  import _cpp = bar;   ?

That doesn't help. foo.func() is still ambiguous. With this proposal, you have hijacked the meaning of namespace lookup. When I say x.y.z, it doesn't just mean look for symbol z in module x/y.d, it can also mean to look for symbol z in C++ namespace x::y. This was not the case with C binding, which continued to use D modules for symbol lookup. Consider that a boatload of C++ code is named std::something. Now, std.string has an ambiguous meaning wherever it is used! -Steve

bar is renamed, thus you have to access via _cpp.[namespace] renames were added to prevent hijacking.
Apr 28 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 28 Apr 2014 10:50:09 -0400, Byron <byron.heads gmail.com> wrote:

 On Mon, 28 Apr 2014 10:45:14 -0400, Steven Schveighoffer wrote:

 On Mon, 28 Apr 2014 10:37:36 -0400, Byron <byron.heads gmail.com> wrote:


 why not  import _cpp = bar;   ?

That doesn't help. foo.func() is still ambiguous. With this proposal, you have hijacked the meaning of namespace lookup. When I say x.y.z, it doesn't just mean look for symbol z in module x/y.d, it can also mean to look for symbol z in C++ namespace x::y. This was not the case with C binding, which continued to use D modules for symbol lookup. Consider that a boatload of C++ code is named std::something. Now, std.string has an ambiguous meaning wherever it is used! -Steve

bar is renamed, thus you have to access via _cpp.[namespace] renames were added to prevent hijacking.

That renames the bar module, but not the foo C++ namespace, which can be assumed when calling foo.func. In reality, you could "fix" the situation by renaming the foo D module, and then foo.func would unambiguously refer to bar's func :) Another alternative fix would be to allow renaming C++ namespaces. I strongly recommend against that. The better alternative is to reserve qualified name lookup to D modules alone. Adding a mechanism that is possibly ugly, but that does NOT conflict with module lookup, in order to disambiguate C++ symbols is fine. -Steve
Apr 28 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Monday, 28 April 2014 at 14:54:17 UTC, Steven Schveighoffer 
wrote:
 Adding a mechanism that is possibly ugly, but that does NOT 
 conflict with module lookup, in order to disambiguate C++ 
 symbols is fine.

Requiring C++ identifiers to be fully qualified with "::" would solve that and encourage writing thin idiomatic D wrappers on top of C++ libs. (and cause a lot of complaints from C++ programmers :-)
Apr 28 2014
prev sibling next sibling parent Byron <byron.heads gmail.com> writes:
On Mon, 28 Apr 2014 10:54:17 -0400, Steven Schveighoffer wrote:

 That doesn't help. foo.func() is still ambiguous. With this proposal,
 you have hijacked the meaning of namespace lookup. When I say x.y.z,
 it doesn't just mean look for symbol z in module x/y.d, it can also
 mean to look for symbol z in C++ namespace x::y. This was not the case
 with C binding, which continued to use D modules for symbol lookup.

 Consider that a boatload of C++ code is named std::something. Now,
 std.string has an ambiguous meaning wherever it is used!

 -Steve

bar is renamed, thus you have to access via _cpp.[namespace] renames were added to prevent hijacking.

That renames the bar module, but not the foo C++ namespace, which can be assumed when calling foo.func. In reality, you could "fix" the situation by renaming the foo D module, and then foo.func would unambiguously refer to bar's func :) Another alternative fix would be to allow renaming C++ namespaces. I strongly recommend against that. The better alternative is to reserve qualified name lookup to D modules alone. Adding a mechanism that is possibly ugly, but that does NOT conflict with module lookup, in order to disambiguate C++ symbols is fine. -Steve

I am confused now, cross module renaming?? I was thinking this: a.d extern(C++, std) { ... class string ... } b.d import std.string; import cpp = a; // a must be accessed via cpp std.string.... /// okay D version cpp.std.string ... /// okay c++ version string ... /// Okay D version cpp.string /// Okay C++ version
Apr 28 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 28 Apr 2014 11:09:38 -0400, Byron <byron.heads gmail.com> wrote:

 I am confused now, cross module renaming??

 I was thinking this:

 a.d
 extern(C++, std) {  ... class string ... }

class string now has two fully-qualified names. a.string, and std.string (assuming the current DIP is implemented).
 b.d
 import std.string;
 import cpp = a; // a must be accessed via cpp

This renames the a *module*, but not the C++ namespace. The C++ namespace is entirely separate from D's module imports. So now, a's string has two names, cpp.string and std.string (still).
 std.string.... /// okay D version

Error. Refers both to the std.string module, and the string class within the std C++ namespace.
 cpp.std.string ... /// okay c++ version

I don't think this would work either. This is a mix of D modules, and C++ namespaces. The DIP does not mention this possibility.
 string ... /// Okay D version

I think this may work.
 cpp.string /// Okay C++ version

Yes. -Steve
Apr 28 2014
prev sibling next sibling parent Byron <byron.heads gmail.com> writes:
On Mon, 28 Apr 2014 11:21:52 -0400, Steven Schveighoffer wrote:

 On Mon, 28 Apr 2014 11:09:38 -0400, Byron <byron.heads gmail.com> wrote:
 
 I am confused now, cross module renaming??

 I was thinking this:

 a.d extern(C++, std) {  ... class string ... }

class string now has two fully-qualified names. a.string, and std.string (assuming the current DIP is implemented).
 b.d import std.string;
 import cpp = a; // a must be accessed via cpp

This renames the a *module*, but not the C++ namespace. The C++ namespace is entirely separate from D's module imports. So now, a's string has two names, cpp.string and std.string (still).
 std.string.... /// okay D version

Error. Refers both to the std.string module, and the string class within the std C++ namespace.
 cpp.std.string ... /// okay c++ version

I don't think this would work either. This is a mix of D modules, and C++ namespaces. The DIP does not mention this possibility.
 string ... /// Okay D version

I think this may work.
 cpp.string /// Okay C++ version

Yes. -Steve

Awesome this help me understand your point. So why does the namespace live outside of the module? They have to live in the imported scope? This seems like a big problem to me. Or I am missing something else? -Byron
Apr 28 2014
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Monday, 28 April 2014 at 14:27:19 UTC, Steven Schveighoffer 
wrote:
 void main()
 {
    func(); // error
    foo.func(); // ALSO error
    bar.func(); // Not error, BUT it's actually calling 
 foo::func from C++ land!
 }

I don't see any fundamental issue here because you can still use renamed imports to disambiguate any call. However it does feel extremely dirty from the reading clarity point of view and can be a good reason to prohibit naive usage of namespaces in D code in same way as modules.
Apr 28 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 28 Apr 2014 11:32:50 -0400, Dicebot <public dicebot.lv> wrote:

 On Monday, 28 April 2014 at 14:27:19 UTC, Steven Schveighoffer wrote:
 void main()
 {
    func(); // error
    foo.func(); // ALSO error
    bar.func(); // Not error, BUT it's actually calling foo::func from  
 C++ land!
 }

I don't see any fundamental issue here because you can still use renamed imports to disambiguate any call. However it does feel extremely dirty from the reading clarity point of view and can be a good reason to prohibit naive usage of namespaces in D code in same way as modules.

Yes, but this proposal gets extra negative points for forcing you to rename your D module for the sake of C++ imports :) For something like std.string, I can't imagine it will be pleasant. -Steve
Apr 28 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 28 Apr 2014 11:29:53 -0400, Byron <byron.heads gmail.com> wrote:

 On Mon, 28 Apr 2014 11:21:52 -0400, Steven Schveighoffer wrote:

 On Mon, 28 Apr 2014 11:09:38 -0400, Byron <byron.heads gmail.com> wrote:

 I am confused now, cross module renaming??

 I was thinking this:

 a.d extern(C++, std) {  ... class string ... }

class string now has two fully-qualified names. a.string, and std.string (assuming the current DIP is implemented).
 b.d import std.string;
 import cpp = a; // a must be accessed via cpp

This renames the a *module*, but not the C++ namespace. The C++ namespace is entirely separate from D's module imports. So now, a's string has two names, cpp.string and std.string (still).
 std.string.... /// okay D version

Error. Refers both to the std.string module, and the string class within the std C++ namespace.
 cpp.std.string ... /// okay c++ version

I don't think this would work either. This is a mix of D modules, and C++ namespaces. The DIP does not mention this possibility.
 string ... /// Okay D version

I think this may work.
 cpp.string /// Okay C++ version

Yes. -Steve

Awesome this help me understand your point. So why does the namespace live outside of the module? They have to live in the imported scope?

Because C++ has no idea of D modules. There are two things here, name mangling, and name lookup. The DIP rightly allows proper name mangling, which is difficult to get right (I think even on different platforms the mangling is different), but also overloads name lookup. So you can access a C++ symbol via it's short name (string), it's fully qualified D name (a.string) or it's fully qualified C++ namespace name (std.string). There is nothing that explains how you could use the module AND the C++ namespace to look up the unambiguous name. But even so, the C++ name conflicts with a D module lookup. And you can only fix it by renaming the D module. I'd rather the DIP not invalidate existing D name lookup, and provide an alternate mechanism to use C++ namespaces for fully qualified symbols. -Steve
Apr 28 2014
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Monday, 28 April 2014 at 14:00:58 UTC, Ola Fosheim Grøstad 
wrote:
 On Monday, 28 April 2014 at 13:47:43 UTC, Steven Schveighoffer 
 wrote:
 Not ok. This is like having 2 definitions for the same 
 function, linker will not accept that.

No. It is like having 2 matching type declarations. The implementation is defined in the C++ source code and is represented as one C++ object/lib file to the linker. The linker will happily accept that.

Linker will yell at you in encrypted klingon, unless the function is weak. Multiple definitions won't work. Also, if you try to call that function, D will probably yell at you as well as your call is ambiguous, and you'll have to specify the module. Why is everybody yelling today ? Can't we have some calm around here ?
Apr 28 2014
prev sibling next sibling parent =?UTF-8?B?U2ltZW4gS2rDpnLDpXM=?= via Digitalmars-d writes:
On 2014-04-28 20:50, Walter Bright via Digitalmars-d wrote:
 On 4/28/2014 7:27 AM, Steven Schveighoffer wrote:
 Consider this code:

 module foo;

 void func() {}

 module bar;

 extern(C) func();

 module prog;

 import foo;
 import bar;

 void main()
 {
     func(); // error
     foo.func(); // ok
     bar.func(); // ok, uses C binding (no name mangling)
 }

 In this case, even though the C function is not mangled or in any other
 namespace, the module can be used for unambiguous calling.

Right.
 module foo;

 void func() {}

 module bar;

 extern(C++, foo) void func(); // foo::func in C++ land

 module prog;

 import foo;
 import bar;

 void main()
 {
     func(); // error
     foo.func(); // ALSO error

No, not an error. Why would it be?

I believe Steven expects things to work this way: module bar; extern(C++, foo) void func(); module prog; import bar; void main() { foo.func(); // Calls bar.func (or is that bar.foo.func?) } -- Simen
Apr 28 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Monday, 28 April 2014 at 19:32:10 UTC, Walter Bright wrote:
 On 4/28/2014 4:29 AM, "Ola Fosheim Grøstad" 
 <ola.fosheim.grostad+dlang gmail.com>" wrote:
 No. Even though they are the same function as far as the 
 signatures are concerned, they are different functions as far 
 as the D type system is concerned, and hence the call is 
 ambiguous. You'll have to qualify by framework1.std.something() 
 or framework2.std.something().

So you have to choose between framework1 and 2's version if std::string when building your own class, an then cast back and forth between the different framework bindings even though the actual type is the same? Isn't that tedious?
 import.std();
 … std.something(); // namespace encapsulation broken or fail?
 … std.coolstuff();

No problem, std.d overrides because it is imported directly and so std is in the current scope. The current scope overrides imported scopes.

But I think that it is a problem that std.something is silently rebound to a different function.
 Still no problem. Qualifying it with framework2 says which one 
 you want.

The problem is that you are forced to qualify the D-binding rather than the path of the cpp function. This will only work out ok if different framework authors cooperate.
 Right, but I want to be sure that the type-system sees all 
 externs with the same
 signature as the same type.

Remember, a C++ signature is the same as its type in C++, but that is not true of D.

And that makes it tedious to interact with C++? But for what gain?
Apr 28 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Monday, 28 April 2014 at 23:57:36 UTC, Walter Bright wrote:
 First off, I expect "std" to be put in core.stdcpp.std, and 
 then imported. So this issue would only happen if 3rd party A 
 and 4th party B each imported 5th party C. Yeah, it'll happen, 
 and it'll still work, as the import system regards the same 
 file as being the same import regardless of the import path 
 used to get to it.

No, it'll happen if they use the same vector library an #include the same "vector3D" and independently specify their own binding? But if they cooperate and use the same binding, then you are ok? That makes no sense.
 It's no different than if you have:

    A::foo()

 in one framework, and a different:

    A::foo()

 in another framework. It won't work in C++, either.

That is only true if you mangle D modules and C++ namespaces the same way. You should be able to have A.foo and A::foo. It makes no sense to conflate the paths if they mangle differently.
 The problem is that you are forced to qualify the D-binding 
 rather than the path
 of the cpp function. This will only work out ok if different 
 framework authors
 cooperate.

Not correct. This is not a problem.

I can mix two independent cpp bindings without casting?
 Remember, a C++ signature is the same as its type in C++, but 
 that is not true
 of D.

And that makes it tedious to interact with C++?

I don't see how it makes it any more tedious than dealing with the ODR rule in C++ anyway.

Why not? It only applies to the translation unit. I see no relationship.
Apr 28 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Tuesday, 29 April 2014 at 06:50:19 UTC, Walter Bright wrote:
 No, it'll happen if they use the same vector library an 
 #include the same
 "vector3D" and independently specify their own binding? But if 
 they cooperate
 and use the same binding, then you are ok? That makes no sense.

I simply don't know what you're talking about when you use the word "binding".

You bind the C++ extern to a D path, and as a result you get 2 types because you have 2 paths rather than one. (according to what you have said) If they mangle to the same name then I want them to be the same type. As a result I am better off when using pure C++ frameworks and creating my own D layer than when I am using 2 mixed D/C++ frameworks that have been developed independently.
 C++ identifiers do not get the module name mangled in.

An therefore they should be seen as the same type!
Apr 29 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Tuesday, 29 April 2014 at 07:50:41 UTC, Walter Bright wrote:
 Basically, Ola, if you could write a piece of sample D code 
 that you feel will not work, please do so.

But I did? framework1.d: extern(C++,veclib){ struct … vec4 …; } extern(C++,physics){ vec4 f(vec4 …) … } framework2.d: extern(C++,veclib){ struct … vec4 …; } extern(C++,graphics){ void g(vec4 …) … } application1.d: import framework1; import framework2; graphics.g( physics.f(…) ); // you said this would not work? ----- myframework.d extern(C++,veclib){ struct … vec4 …; } extern(C++,physics){ vec4 f(vec4 …) … } extern(C++,graphics){ void g(vec4 …) … } application2.d import myframework; graphics.g( physics.f(…) ); // but now it works?
Apr 29 2014
prev sibling next sibling parent =?UTF-8?B?U2ltZW4gS2rDpnLDpXM=?= via Digitalmars-d writes:
On 2014-04-28 21:06, Walter Bright via Digitalmars-d wrote:
 On 4/28/2014 2:00 PM, Simen Kjærås via Digitalmars-d wrote:
 I believe Steven expects things to work this way:

 module bar;

 extern(C++, foo) void func();


 module prog;

 import bar;

 void main()
 {
     foo.func(); // Calls bar.func (or is that bar.foo.func?)
 }

It would call bar.foo.func(). But your example is different from Steven's.

It is. That was kinda the point. :p Building on this knowledge: module foo; void func(); module bar; extern(C++, foo) void func(); module prog; import foo; import bar; void main() { // Seems like it's ambiguous between foo.func and bar.foo.func. foo.func(); } -- Simen
Apr 29 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 28 Apr 2014 17:00:11 -0400, Simen Kj=C3=A6r=C3=A5s via Digitalma=
rs-d  =

<digitalmars-d puremagic.com> wrote:

 On 2014-04-28 20:50, Walter Bright via Digitalmars-d wrote:
 On 4/28/2014 7:27 AM, Steven Schveighoffer wrote:
 Consider this code:

 module foo;

 void func() {}

 module bar;

 extern(C) func();

 module prog;

 import foo;
 import bar;

 void main()
 {
     func(); // error
     foo.func(); // ok
     bar.func(); // ok, uses C binding (no name mangling)
 }

 In this case, even though the C function is not mangled or in any ot=



 namespace, the module can be used for unambiguous calling.

Right.
 module foo;

 void func() {}

 module bar;

 extern(C++, foo) void func(); // foo::func in C++ land

 module prog;

 import foo;
 import bar;

 void main()
 {
     func(); // error
     foo.func(); // ALSO error

No, not an error. Why would it be?

I believe Steven expects things to work this way: module bar; extern(C++, foo) void func(); module prog; import bar; void main() { foo.func(); // Calls bar.func (or is that bar.foo.func?) }

Yes, exactly. That is what the DIP says: "Declarations in the namespace can be accessed without qualification in = = the enclosing scope if there is no ambiguity. Ambiguity issues can be = resolved by adding the namespace qualifier" Which then proceeds to show that only the namespace qualifier is needed= = to disambiguate the symbol. -Steve
Apr 29 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 29 Apr 2014 11:47:28 -0400, Timon Gehr <timon.gehr gmx.ch> wrote:

 On 04/29/2014 02:01 PM, Steven Schveighoffer wrote:
 That is what the DIP says:

 "Declarations in the namespace can be accessed without qualification in
 the enclosing scope if there is no ambiguity. Ambiguity issues can be
 resolved by adding the namespace qualifier"

 Which then  proceeds to show that only the namespace qualifier is needed
 to disambiguate the symbol.

 -Steve

You seem to be missing the only important statement that the DIP makes about symbol disambiguation, that follows straight after those examples: "Name lookup rules are the same as for mixin templates." (Maybe it should say 'named template mixins'.)

I am not familiar with the rules. Perhaps you can just outline for me: module bar; extern(C++, foo) void func(); module prog; import bar; void main() { foo.func(); // works? } If this works, then we have a problem. If it doesn't work, well, then I see nobody using this feature (using C++ namespace for disambiguation, not the mangling, which is still useful). -Steve
Apr 29 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 29 Apr 2014 12:03:02 -0400, Timon Gehr <timon.gehr gmx.ch> wrote:

 On 04/29/2014 05:52 PM, Steven Schveighoffer wrote:
 I am not familiar with the rules.

 Perhaps you can just outline for me:

 module bar;

 extern(C++, foo) void func();

 module prog;

 import bar;

 void main()
 {
     foo.func(); // works?
 }

 If this works, then we have a problem.

It does work. What happens is analogous to: module bar; void func(){} module prog; import bar; void func(){} void main(){ func(); } I.e. if you add a new symbol to your own module, then this identifier will be hidden, no questions asked. Importing a module adds a new symbol of its name to your module. I'm not sure why you see this as a problem. The name lookup rules are designed such that changes in one module cannot silently change name lookup in _another_ module, but anything may happen to lookup in the same module.

OK, so you are saying that from a module different than the one that defines the namespace/function, I can call it via it's full namespace. But what happens when you add another import that conflicts? module foo; void func() {} module prog; // updated import bar; import foo; void main(){ foo.func(); // now calls foo.func, and not bar.func as it originally did, right? } So by importing from another module, we have silently and drastically changed the behavior. Have I missed something? Why is this not a problem? -Steve
Apr 29 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 29 Apr 2014 15:52:01 -0400, Walter Bright  =

<newshound2 digitalmars.com> wrote:

 On 4/29/2014 9:13 AM, Steven Schveighoffer wrote:
 But what happens when you add another import that conflicts?

 module foo;

 void func() {}

 module prog; // updated
 import bar;
 import foo;

 void main(){
     foo.func(); // now calls foo.func, and not bar.func as it  =


 originally did,
 right?
 }

 So by importing from another module, we have silently and drastically=


 changed
 the behavior. Have I missed something?

 Why is this not a problem?

Because the compiler would now issue an error for that, it's its =

 anti-hijacking feature.

 Try it and see!

I agree! that was my central point, which Timon seemed to be arguing = against :) Quoting: On Tue, 29 Apr 2014 11:43:45 -0400, Timon Gehr <timon.gehr gmx.ch> wrote= :
 On 04/29/2014 01:34 PM, Simen Kj=C3=A6r=C3=A5s via Digitalmars-d wrote=

 Building on this knowledge:

 module foo;

 void func();


 module bar;

 extern(C++, foo) void func();


 module prog;

 import foo;
 import bar;

 void main()
 {
      // Seems like it's ambiguous between foo.func and bar.foo.func.
      foo.func();
 }

It will call foo.func, because the module foo is in scope in module pr=

 and hence hides the namespace foo in module bar.

 You can already try this today, as the DIP _does not actually introduc=

 any new lookup rules_:

 module a;
 void func(){}
 //---
 module bar;

 mixin template X(){
      void func();
 }
 mixin X foo;
 //---
 import foo,bar;

 void main(){
      foo.func();
 }

 In particular, any problems you find with symbol lookup are actually  =

 orthogonal to the DIP.

-Steve
Apr 29 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Tuesday, 29 April 2014 at 19:48:36 UTC, Walter Bright wrote:
 I'd do your example as:

 vec.d:
 extern(C++,veclib){ struct … vec4 …; }

 framework1.d:
 import vec;
 extern(C++,physics){ vec4 f(vec4 …) … }

 framework2.d:
 import vec;
 extern(C++,graphics){ void g(vec4 …) … }

Yes, but that requires the authors of framework1 and framework2 to cooperate. Which is why you with this DIP will end up with people being better off by using pure C++ rather than mixed D/C++ from different sources. With "graphics::g(physics::f(…))" this would not have been an issue.
Apr 29 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 29 Apr 2014 16:00:43 -0400, Steven Schveighoffer  
<schveiguy yahoo.com> wrote:

 On Tue, 29 Apr 2014 15:52:01 -0400, Walter Bright  
 <newshound2 digitalmars.com> wrote:

 Because the compiler would now issue an error for that, it's its  
 anti-hijacking feature.

 Try it and see!

I agree! that was my central point, which Timon seemed to be arguing against :)

And in fact, so were you! On Mon, 28 Apr 2014 16:50:45 -0400, Walter Bright <newshound2 digitalmars.com> wrote:
 On 4/28/2014 7:27 AM, Steven Schveighoffer wrote:
 module foo;

 void func() {}

 module bar;

 extern(C++, foo) void func(); // foo::func in C++ land

 module prog;

 import foo;
 import bar;

 void main()
 {
     func(); // error
     foo.func(); // ALSO error

No, not an error. Why would it be?

This is EXACTLY the same code that you said would now be an error above! I think you guys need to reexamine this, and choose one way or another. At this point, I have no clue as to how it's supposed to work. -Steve
Apr 29 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Tuesday, 29 April 2014 at 20:33:07 UTC, Walter Bright wrote:
 Not really. It is reasonable to expect that when Framework1 and 
 Framework2 each import 4th party Vec, that they do it with an 
 import rather than inlining Vec's declarations.

Vectors are not the best example since one library might use struct{float x,y,z,w;} and another use float[4], but that would be too complicated to unify on the D side without a wrapper. At least as far as I can tell. (I.e. the C++ frameworks interoperate because the memory layout and semantics are the same, although the types are not.)
 With "graphics::g(physics::f(…))" this would not have been an 
 issue.

Having an alternative lookup method is a large increase in language complexity.

I wouldn't mind using fully qualified names, but others probably would.
It does occur to me that two C++ symbols in the same namespace 
may be regarded as the same by the lookup code. That may be a 
reasonable enhancement request.

Yes, that would help.
Apr 29 2014
prev sibling next sibling parent "Brian Schott" <briancschott gmail.com> writes:
On Monday, 28 April 2014 at 01:18:04 UTC, Walter Bright wrote:
 This is the new grammar?

 LinkageAttribute:
     'extern' '(' identifier '++'? (',' identifier)? ')'

You can also have N.M

I've updated the DIP page to include documentation of the change to the language grammar.
Apr 29 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 29 Apr 2014 17:38:07 -0400, Timon Gehr <timon.gehr gmx.ch> wrote:

 On 04/29/2014 10:49 PM, Steven Schveighoffer wrote:
 On Tue, 29 Apr 2014 16:00:43 -0400, Steven Schveighoffer
 <schveiguy yahoo.com> wrote:

 On Tue, 29 Apr 2014 15:52:01 -0400, Walter Bright
 <newshound2 digitalmars.com> wrote:

 Because the compiler would now issue an error for that, it's its
 anti-hijacking feature.

 Try it and see!

I agree! that was my central point, which Timon seemed to be arguing against :)

And in fact, so were you! ... This is EXACTLY the same code that you said would now be an error above!

Maybe he didn't notice that you changed the 'main' function relative to my post. If you don't mention 'foo' explicitly, then obviously it cannot be hidden by the import and the code is in error.

I never changed the code. It always was foo.func(). That was my point.
 I think you guys  need to reexamine this,

Not me. I typically test my claims even if I am sure, if only to file bug reports.

Your view has been consistent. I think it defeats the purpose of having namespaces to disambiguate calls, since the disambiguation itself conflicts with modules. If foo.func means one thing today and another thing tomorrow, based on an import, I think the feature is flawed. Template namespaces are just as flawed.
 and choose one way or another.
 At this point, I have no clue as to how it's supposed to work.

Obviously you did not actually try. :P

No, I get what you are saying. The above statement is because I'm getting conflicting reports from Walter.
 Again, to make it really easy for you to test the behaviour:

 module foo;
 import std.stdio;

 int func(){ writeln("hello from foo!"); return 1; }

 //---

 module bar;
 import std.stdio;

 mixin template X(){
      int func(){ writeln("hello from bar!"); return 2; }
 }
 mixin X foo;

 //---

 module prog;

 void main(){
      void onlybar(){
          import bar;
          auto r=foo.func(); // hello from bar!
          assert(r==2); // pass!
      }
      void fooandbar(){
          import bar,foo;
          auto r=foo.func(); // hello from foo!
          assert(r==1); // pass!
      }
      onlybar();
      fooandbar();
 }

Wouldn't a similar test be to create a struct for a namespace? The confusing issue here to C++ programmers is, when I specify x::y::z, it means z in namespace x::y, regardless of where it was imported. If in D we say you can access this via x.y.z, they are going to think they can always type that. To have it so easily break is not a good thing.
 http://dlang.org/download.html

 $ dmd prog foo bar && ./prog
 hello from bar!
 hello from foo!

 This is because the import of module 'foo' hides the namespace 'foo'  
 imported from 'bar' in the scope of 'fooandbar'. It is not 'func' that  
 is being hidden, but 'foo'.

In fact, it's the entire foo namespace. module bar; import std.stdio; mixin template X(){ int func(){ writeln("hello from bar!"); return 2; } int func2(){ writeln("hello also from bar!"); return 2;} // no equivalent in foo.d } mixin X foo; module foo; // same as before ... module prog; import foo; // comment out to compile import bar; void main() { foo.func2(); // Error: undefined identifier 'func2', did you mean 'function func'? } So basically any namespace that matches the root phobos import path will cause conflicts. You don't suppose any C++ code uses that do you? ;) -Steve
Apr 29 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Tuesday, 29 April 2014 at 22:51:42 UTC, Andrei Alexandrescu 
wrote:
 On 4/29/14, 12:49 PM, Walter Bright wrote:
 On 4/29/2014 8:43 AM, Timon Gehr wrote:
 as the DIP _does not actually introduce any new lookup rules_
 [...]
 In particular, any problems you find with symbol lookup are 
 actually
 orthogonal
 to the DIP.

Yes!

This is a biggie. KISS etc. -- Andrei

KISS: keep 'em seperate !KISS: map language 1 onto language 2 Wrong KISS: compiler internals over specification
Apr 29 2014
prev sibling next sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Wed, 30 Apr 2014 05:03:58 +0100, Ola Fosheim Gr=F8stad  =

<ola.fosheim.grostad+dlang gmail.com> wrote:
 Wrong KISS: compiler internals over specification

Indeed. I've been a C/C++ developer for ~16 years and I was confused several tim= es = reading this thread. The mix of D modules and C++ namespaces is the thing what needs to be ke= pt = simple for us lesser mortals, not the compiler implementation - which = should, I agree, *ideally* remain simple, but in this case should be = sacrificed for the other because compiler writers are good at what they = do = and will be able to cope. I think it is simpler all round to just invent (and perhaps reserve) a n= ew = top level module for C++ namespaces (an idea mentioned here already) i.e= . = "cpp" Example: module a; extern(C++, std) class string {..} // identical to decl in b module b: extern(C++, std) class string {..} // identical to decl in a extern(C++, std) class vector {..} // new decl module userland; import a; import b; void main() { cpp.std.string x =3D new cpp.std.string(); cpp.std.vector y =3D new cpp.std.vector(); } Notes: - the D modules 'a' and 'b' play no part whatsoever in the lookup of t= he = C++ symbol (why the hell should they? I see no benefit to this) - the identical declarations in a/b for std.string are treated as one.= - any *use* (in userland) of a non-identical/ambiguous declaration wou= ld = result in an error. Link time is where it would actually complain if multiple C++ symbols we= re = found. Special lookup rules would apply to cpp.* My 2p/c R -- = Using Opera's revolutionary email client: http://www.opera.com/mail/
Apr 30 2014
prev sibling next sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Wed, 30 Apr 2014 10:20:22 +0100, Regan Heath <regan netmail.co.nz>  
wrote:

Something else to think about.

C# has the same problem and has solved it the following way..

[main.cs]
using ..
using CSTest_Test1;
using CSTest_Test2;

namespace CSTest
{
     class Program
     {
         static void Main(string[] args)
         {
             Test1.GetLastError(); // class, not namespace required to call  
method
             Test2.GetLastError(); // class, not namespace required to call  
method
         }
     }
}

[Test1.cs]
using ..
namespace CSTest_Test1
{
     public static class Test1
     {
         [DllImport("coredll.dll", SetLastError = true)]
         public static extern Int32 GetLastError();
     }
}

[Test2.cs]
namespace CSTest_Test2
{
     public static class Test2
     {
         [DllImport("coredll.dll", SetLastError = true)]
         public static extern Int32 GetLastError();
     }
}

GetLastError() is always going to unambiguous here because it *must* live  
inside a C# class and that class name is *always* required in the call to  
it.

If D has replaced classes/namespaces with modules, then the answer to our  
problem may be to use the C++ namespace *only* to mangle the symbol, and  
*only* use the D module for lookup resolution.

module a;
extern(C++, std) class string {..}

module b:
extern(C++, std) class string {..}
extern(C++, std) class vector {..}

module userland;
import a;
import b;

void main()
{
   string x = new string();     //error ambiguous (same resolution as for D  
symbols)
   a.string x = new a.string(); //ok
   b.vector y = new b.vector(); //ok
}

Regan
Apr 30 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 30 Apr 2014 15:56:15 -0400, Timon Gehr <timon.gehr gmx.ch> wrote:

 On 04/30/2014 02:41 AM, Steven Schveighoffer wrote:
 Wouldn't a similar test be to create a struct for a namespace?
 ...

Yes, and this behaves the same in this specific case.

Just a note of friendly advice, most people understand using struct/class as a namespace than mixing in a template (including myself).
 The confusing issue here to C++ programmers is, when I specify x::y::z,
 it means z in namespace x::y, regardless of where it was imported. If in
 D we say you can access this via x.y.z, they are going to think they can
 always type that. To have it so easily break is not a good thing.
 ...

If this is a problem, I guess the most obvious alternatives are to: 1. Get rid of namespace scopes. Require workarounds in the case of conflicting definitions in different namespaces in the same file. (Eg. use a mixin template.) I'd presume this would not happen often.

You mean use the syntax just to give mangling info? I think that would be OK. Another option I thought of is to alias the symbol before exiting the namespace scope (and still disallow namespace lookup): extern(C++, std){ class string {...} alias std_string = string; // std_string not likely to be in conflict. } std.string would not refer to string above, ever. I think it would be useful to be able to specify an alias in one line also: extern(C++, std) alias std_string = string; Of course, such a system does not scale well, but it would fit within D's lookup rules.
 2. Give the global C++ namespace a distinctive name and put all other  
 C++ namespaces below it. This way fully qualified name lookup will be  
 reliable.

This was my suggestion as well.
 This is because the import of module 'foo' hides the namespace 'foo'
 imported from 'bar' in the scope of 'fooandbar'. It is not 'func' that
 is being hidden, but 'foo'.

In fact, it's the entire foo namespace. ...

Yes, but this is visible in the file that is being changed.

We have supposedly told C++ developers "if your C++ symbol is ambiguous, disambiguate using the namespace." This won't always work, and the result is going to be ugly and super-confusing.
 So basically any namespace that matches the root phobos import path will
 cause conflicts. You don't suppose any C++ code uses that do you? ;)

How many C++ standard headers contain conflicting symbol names in different namespaces? If the namespace symbol really needs to be addressable, there could be an alias. eg. alias cpp=std;

There probably are few that contain competing names. I'm more concerned about namespaces that D has copied from C++. Many in std.algorithm, std.string, etc. Using C++ namespace std is going to result in quite a bit of confusion and conflict I think. -Steve
Apr 30 2014
prev sibling next sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Wed, 30 Apr 2014 20:56:15 +0100, Timon Gehr <timon.gehr gmx.ch> wrote:
 If this is a problem, I guess the most obvious alternatives are to:

 1. Get rid of namespace scopes. Require workarounds in the case of  
 conflicting definitions in different namespaces in the same file. (Eg.  
 use a mixin template.) I'd presume this would not happen often.

 2. Give the global C++ namespace a distinctive name and put all other  
 C++ namespaces below it. This way fully qualified name lookup will be  
 reliable.

3. Use the C++ namespace for mangling, but not lookup. C++ symbols will belong in the module they are imported into, and be treated exactly the same as a D symbol, e.g. module a; extern(C++, std) ..string.. module b; extern(C++, std) ..string.. module c; import a; import b; void main() { .. string .. } // error could be a.string or b.string void main() { .. a.string .. } // resolved R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
May 01 2014
prev sibling next sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Thu, 01 May 2014 11:03:21 +0100, Regan Heath <regan netmail.co.nz>  
wrote:

 On Wed, 30 Apr 2014 20:56:15 +0100, Timon Gehr <timon.gehr gmx.ch> wrote:
 If this is a problem, I guess the most obvious alternatives are to:

 1. Get rid of namespace scopes. Require workarounds in the case of  
 conflicting definitions in different namespaces in the same file. (Eg.  
 use a mixin template.) I'd presume this would not happen often.

 2. Give the global C++ namespace a distinctive name and put all other  
 C++ namespaces below it. This way fully qualified name lookup will be  
 reliable.

3. Use the C++ namespace for mangling, but not lookup. C++ symbols will belong in the module they are imported into, and be treated exactly the same as a D symbol, e.g. module a; extern(C++, std) ..string.. module b; extern(C++, std) ..string.. module c; import a; import b; void main() { .. string .. } // error could be a.string or b.string void main() { .. a.string .. } // resolved

Sorry, #1 is the same suggestion :) R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
May 01 2014
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/27/2014 12:54 PM, Walter Bright wrote:
 http://wiki.dlang.org/DIP61

Now with pull request: https://github.com/D-Programming-Language/dmd/pull/3517
May 01 2014
next sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 1 May 2014 at 18:44:36 UTC, Walter Bright wrote:
 On 4/27/2014 12:54 PM, Walter Bright wrote:
 http://wiki.dlang.org/DIP61

Now with pull request: https://github.com/D-Programming-Language/dmd/pull/3517

Does that create a new named scope ? And regular D identifier resolution rule ? IF yes, that's awesome news !
May 01 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 5/1/2014 5:33 PM, deadalnix wrote:
 On Thursday, 1 May 2014 at 18:44:36 UTC, Walter Bright wrote:
 On 4/27/2014 12:54 PM, Walter Bright wrote:
 http://wiki.dlang.org/DIP61

Now with pull request: https://github.com/D-Programming-Language/dmd/pull/3517

Does that create a new named scope ?

Yes.
 And regular D identifier resolution rule ?

Yes.
 IF yes, that's awesome news !

I am rather pleased with how it turned out :-)
May 01 2014
parent Walter Bright <newshound2 digitalmars.com> writes:
On 5/2/2014 6:53 AM, Steven Schveighoffer wrote:
 Can you explain to people who don't understand DMD code, does this exactly
 implement the DIP?

Yes.
 The two questions above imply that the DIP isn't enough to
 answer those questions...

It follows the scoping and name resolution rules used for template mixins.
May 02 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 01 May 2014 21:44:10 -0400, Walter Bright  
<newshound2 digitalmars.com> wrote:

 On 5/1/2014 5:33 PM, deadalnix wrote:
 On Thursday, 1 May 2014 at 18:44:36 UTC, Walter Bright wrote:
 On 4/27/2014 12:54 PM, Walter Bright wrote:
 http://wiki.dlang.org/DIP61

Now with pull request: https://github.com/D-Programming-Language/dmd/pull/3517

Does that create a new named scope ?

Yes.
 And regular D identifier resolution rule ?

Yes.
 IF yes, that's awesome news !

I am rather pleased with how it turned out :-)

Can you explain to people who don't understand DMD code, does this exactly implement the DIP? The two questions above imply that the DIP isn't enough to answer those questions... -Steve
May 02 2014
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 02 May 2014 15:06:13 -0400, Walter Bright  
<newshound2 digitalmars.com> wrote:

 On 5/2/2014 6:53 AM, Steven Schveighoffer wrote:
 Can you explain to people who don't understand DMD code, does this  
 exactly
 implement the DIP?

Yes.
 The two questions above imply that the DIP isn't enough to
 answer those questions...

It follows the scoping and name resolution rules used for template mixins.

OK, the questions (that I didn't understand) gave me the impression that you did something different from the DIP. -Steve
May 02 2014
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 1 May 2014 at 10:03:21 UTC, Regan Heath wrote:
 On Wed, 30 Apr 2014 20:56:15 +0100, Timon Gehr 
 <timon.gehr gmx.ch> wrote:
 If this is a problem, I guess the most obvious alternatives 
 are to:

 1. Get rid of namespace scopes. Require workarounds in the 
 case of conflicting definitions in different namespaces in the 
 same file. (Eg. use a mixin template.) I'd presume this would 
 not happen often.

 2. Give the global C++ namespace a distinctive name and put 
 all other C++ namespaces below it. This way fully qualified 
 name lookup will be reliable.

3. Use the C++ namespace for mangling, but not lookup. C++ symbols will belong in the module they are imported into, and be treated exactly the same as a D symbol, e.g.

1. The whole point of C++ namespace is to avoid that. That is going to happen. Probably less in D as we have module scoping. But that makes it impossible to port many C++ headers. 2. Creating a new name lookup mechanism is the kind of idea that sound good but ends up horribly backfiring. There is all kind of implications and it affect every single identifier resolution. You don't want to mess with that (especially since it is already quite badly defined in the first place). 3. That makes it impossible to port some C++ headers just as 1.
May 01 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Friday, 2 May 2014 at 00:22:14 UTC, deadalnix wrote:
 2. Creating a new name lookup mechanism is the kind of idea 
 that sound good but ends up horribly backfiring. There is all 
 kind of implications and it affect every single identifier 
 resolution. You don't want to mess with that (especially since 
 it is already quite badly defined in the first place).

What implications? The implications with this DIP is that all library authors will have to follow a convention of having all C++ dependencies in a module named "cpp" in order to have a "fake" way of specifying fully qualified C++ names. Then lobby for coercing C++ types that have different paths. This is not elegant. It is a hack.
May 02 2014
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Friday, 2 May 2014 at 07:44:50 UTC, Walter Bright wrote:
 Not at all, any more than you have to do that for C names.

The difference is that C names tend to have their namespace embedded: framework_structname_function()
May 02 2014
prev sibling next sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Fri, 02 May 2014 01:22:12 +0100, deadalnix <deadalnix gmail.com> wrote:

 On Thursday, 1 May 2014 at 10:03:21 UTC, Regan Heath wrote:
 On Wed, 30 Apr 2014 20:56:15 +0100, Timon Gehr <timon.gehr gmx.ch>  
 wrote:
 If this is a problem, I guess the most obvious alternatives are to:

 1. Get rid of namespace scopes. Require workarounds in the case of  
 conflicting definitions in different namespaces in the same file. (Eg.  
 use a mixin template.) I'd presume this would not happen often.

 2. Give the global C++ namespace a distinctive name and put all other  
 C++ namespaces below it. This way fully qualified name lookup will be  
 reliable.

3. Use the C++ namespace for mangling, but not lookup. C++ symbols will belong in the module they are imported into, and be treated exactly the same as a D symbol, e.g.

1. The whole point of C++ namespace is to avoid that. That is going to happen. Probably less in D as we have module scoping. But that makes it impossible to port many C++ headers. 2. Creating a new name lookup mechanism is the kind of idea that sound good but ends up horribly backfiring. There is all kind of implications and it affect every single identifier resolution. You don't want to mess with that (especially since it is already quite badly defined in the first place). 3. That makes it impossible to port some C++ headers just as 1.

#1 and #3 are essentially the same thing, and are how C# interfaces with .. well C, not C++ granted. But, how does this make it impossible to port some C++ headers? Were you thinking.. [a.cpp/h] namespace a { void foo(); } [b.cpp/h] namespace b { void foo(); } [header.h] <- header to import #include "a.h" #include "b.h" [my.d] <- our port extern(c++, a) foo(); extern(c++, b) foo(); // oh, oh! ? Because the solution is.. [a.d] extern(c++, a) foo(); [b.d] extern(c++, b) foo(); [my.d] import a; import b; // resolve the conflict using the existing D mechanisms, or call them using a.foo, b.foo. In essence we're re-defining the C++ namespace(s) as a D one(s) and we have complete flexibility about how we do it. We can expose C++ symbols in any D namespace we like, we can hide/pack others away in a cpp or util namespace if we prefer. R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
May 02 2014
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Friday, 2 May 2014 at 09:25:34 UTC, Ola Fosheim Grøstad wrote:
 On Friday, 2 May 2014 at 07:44:50 UTC, Walter Bright wrote:
 Not at all, any more than you have to do that for C names.

The difference is that C names tend to have their namespace embedded: framework_structname_function()

You are only proving that you are missing the point completely.
May 02 2014
prev sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Friday, 2 May 2014 at 17:34:49 UTC, deadalnix wrote:
 framework_structname_function()

You are only proving that you are missing the point completely.

Then I ask you to be graceful and explain it to me.
May 02 2014