digitalmars.D - module madness
- John Stoneham (42/42) Feb 10 2006 I hope I'm not retreading old ground. I've been browsing the archives
- Lars Ivar Igesund (3/56) Feb 10 2006 Sounds like something I reported with testcases 2 years ago :P Don't
- John Stoneham (79/79) Feb 12 2006 There is definitely a bug in the module namespace parsing. The code
-
=?ISO-8859-1?Q?Jari-Matti_M=E4kel=E4?=
(14/26)
Feb 15 2006
- =?ISO-8859-1?Q?Jari-Matti_M=E4kel=E4?= (22/49) Feb 16 2006 Here's a solution proposal:
I hope I'm not retreading old ground. I've been browsing the archives for a while on this issue and I haven't seen this particular problem addressed. If I've overlooked it, I apologize. ------begin stuff.d----------- module stuff; private import std.stdio; [...] -------end stuff.d----------- -------begin main.d---------- private import stuff.d void main() { std.stdio.writefln("Hello crazy world!"); } --------end main.d----------- Correct me if I'm wrong, but doesn't "private import std.stdio;" in stuff.d make the import of std.stdio private to that module? That *is* the way it's supposed to work, right? So how am I able to reference std.stdio in the above code without an error? This behavior led me to a somewhat frustrating experience. I'm working on a project that has about 10 modules. One of these modules contains global variables (not classes) that several other modules need (and also need to sometimes change). A couple of those modules also reference each other, and every import in every module is "private import". However, in the main program file I was qualifying the globals as globals.whatever and didn't realize that I hadn't "private import"ed the globals module there at all; but since another module had imported it and that module was imported in the main file, I could access it using qualified notation. And now for the really weird part: When the main file doesn't import the globals module, some of the other modules which "private import" it complain that it now conflicts with the "private import" of that globals module in another module. But it shouldn't conflict at all! All imports are "private import" and there are no name clashes in any of the modules in any case. And simply importing the globals module in the main file causes the other conflicts to be resolved somehow, although no other change was made to any module. I can give a small example using 3 very short modules if my explanation here wasn't clear. This behavior makes no sense to me! Can someone please explain why this is happening? I realize that the private/public module namespace issue has been done to death, but I thought I understood it until this problem. --John
Feb 10 2006
John Stoneham wrote:I hope I'm not retreading old ground. I've been browsing the archives for a while on this issue and I haven't seen this particular problem addressed. If I've overlooked it, I apologize. ------begin stuff.d----------- module stuff; private import std.stdio; [...] -------end stuff.d----------- -------begin main.d---------- private import stuff.d void main() { std.stdio.writefln("Hello crazy world!"); } --------end main.d----------- Correct me if I'm wrong, but doesn't "private import std.stdio;" in stuff.d make the import of std.stdio private to that module? That *is* the way it's supposed to work, right? So how am I able to reference std.stdio in the above code without an error? This behavior led me to a somewhat frustrating experience. I'm working on a project that has about 10 modules. One of these modules contains global variables (not classes) that several other modules need (and also need to sometimes change). A couple of those modules also reference each other, and every import in every module is "private import". However, in the main program file I was qualifying the globals as globals.whatever and didn't realize that I hadn't "private import"ed the globals module there at all; but since another module had imported it and that module was imported in the main file, I could access it using qualified notation. And now for the really weird part: When the main file doesn't import the globals module, some of the other modules which "private import" it complain that it now conflicts with the "private import" of that globals module in another module. But it shouldn't conflict at all! All imports are "private import" and there are no name clashes in any of the modules in any case. And simply importing the globals module in the main file causes the other conflicts to be resolved somehow, although no other change was made to any module. I can give a small example using 3 very short modules if my explanation here wasn't clear. This behavior makes no sense to me! Can someone please explain why this is happening? I realize that the private/public module namespace issue has been done to death, but I thought I understood it until this problem. --JohnSounds like something I reported with testcases 2 years ago :P Don't remember the details anymore though.
Feb 10 2006
There is definitely a bug in the module namespace parsing. The code below demonstrates the bug, which is first evident as being able to access a module's variables/functions even though it hasn't been imported. In the code below 3 modules are defined and used in the main program. The first module, notes, simply declares an enum which is used by the other modules. The second, printer, contains one function which returns a string representation of the enum. The third, compose, contains one function which combines 3 of the string representations of the enum into one longer string, using the function defined in printer to return a string. (Don't worry about whether this is "good code", I just threw it together as a quick example to demonstrate the bug.) In the main file, 3 lines are commented out and numbered with a comment at the end of the line. When the 3 lines are commented out, the program compiles fine, even though in main.d there is no import of notes and the enum defined there is accessed using qualified notation. THIS IS A BUG AND SHOULD BE GENERATE AN ERROR WHEN COMPILED. According the documentation: If the import is private, such as: module abc; private import def; then def is not searched when another module imports abc. So when main imports compose, notes should not be searched (according to the spec) and main should know NOTHING about the definitions in notes. Trying to access a name local to notes when notes is not imported should generate a compile-time error. The problem exposes itself further when the lines (1) and (3) are uncommented. When this is done, the compiler generates an error stating "compose.d(4): import compose.notes conflicts with printer.notes at printer.d(3)" THERE IS NO CONFLICT. Both modules use "private import" to import notes. When line 1 is uncommented and both compose and printer are imported into main, each one has "private import notes" and the compiler should not "search" notes twice. If it is not an error to allow qualified notation to access a sub-module privately-imported by an imported module (although it should be), then there is a bug in the way the compiler parses the module namespaces and claiming a conflict which does not exist. When line 2 is uncommented the program compiles fine. Notice that no change was made to any of the modules to fix the compile errors once they appeared. The only change was importing into main the module that the other modules also import. -----begin notes.d----- module notes; enum { Do, Re, Mi, Fa, So, La, Ti } ------end notes.d------ -----begin printer.d----- module printer; private import notes; char[] print_note(uint a) { static char[][7] notes_str = ["Do", "Re", "Mi", "Fa", "So", "La", "Ti"]; // range check omitted return notes_str[a]; } ------end printer.d------ -----begin compose.d----- module compose; private import printer; private import notes; char[] chord(uint a, uint b, uint c) { if (a <= Ti && b <= Ti && c <= Ti) return print_note(a) ~ "+" ~ print_note(b) ~ "+" ~ print_note(c); else return ""; } ------end compose.d------ -----begin main.d----- import std.stdio; private import compose; //private import printer; // (1) //private import notes; // (2) void main() { writefln("chord of Do+Mi+So = %s", chord(notes.Do, notes.Mi, notes.So)); //writefln("note %d = %s", notes.Mi, print_note(notes.Mi)); // (3) } ------end main.d------
Feb 12 2006
John Stoneham wrote:There is definitely a bug in the module namespace parsing. The code below demonstrates the bug, which is first evident as being able to access a module's variables/functions even though it hasn't been imported. In the code below 3 modules are defined and used in the main program. The first module, notes, simply declares an enum which is used by the other modules. The second, printer, contains one function which returns a string representation of the enum. The third, compose, contains one function which combines 3 of the string representations of the enum into one longer string, using the function defined in printer to return a string. (Don't worry about whether this is "good code", I just threw it together as a quick example to demonstrate the bug.)<snip> Thank you John for the "practical" example. This is the biggest problem I've had with D since my very first "big" project in 2003. I like the way it is written in the docs, but this implementation is terribly broken. It's practically impossible to create a project with >= 3 modules without using some quirks with imports (to avoid namespace conflicts). I think it shouldn't be allowed to access privately imported module members at all. Of course it improves flexibility to have access to every possible symbol everywhere in the program, but what's the point with visibility keywords then? Walter, can you please finally fix this? -- Jari-Matti
Feb 15 2006
Jari-Matti Mäkelä wrote:John Stoneham wrote:Here's a solution proposal: I think the problem is that the compiler only keeps track of the "latest" module in the import chain. If the same symbol is imported using >= 2 different paths, the compiler regards these symbols as completely separate. Is there any possibility to include some sort of additional information that tells the "origin" of the symbol so that the compiler would be able to merge these identical symbols as one. "origin" = where the symbol was last declared/(re)implemented in one import chain The only chance of conflict I can think of is when the symbol contents are "tampered" along the way and two symbols with different implementations are introduced in the same module. Should we use some kind of simplified c++ multiple inheritance rules here then? Simplified, because D modules cannot inherit. I think this would be an elegant solution since it would not only allow the compiler to "pollute" the symbol namespace with private symbols and thus giving more precise error messages than C/C++ with the help of the symbol table, but also prevent conflicts with these "intelligent" merging rules. -- Jari-MattiThere is definitely a bug in the module namespace parsing. The code below demonstrates the bug, which is first evident as being able to access a module's variables/functions even though it hasn't been imported. In the code below 3 modules are defined and used in the main program. The first module, notes, simply declares an enum which is used by the other modules. The second, printer, contains one function which returns a string representation of the enum. The third, compose, contains one function which combines 3 of the string representations of the enum into one longer string, using the function defined in printer to return a string. (Don't worry about whether this is "good code", I just threw it together as a quick example to demonstrate the bug.)<snip> Thank you John for the "practical" example. This is the biggest problem I've had with D since my very first "big" project in 2003. I like the way it is written in the docs, but this implementation is terribly broken. It's practically impossible to create a project with >= 3 modules without using some quirks with imports (to avoid namespace conflicts). I think it shouldn't be allowed to access privately imported module members at all. Of course it improves flexibility to have access to every possible symbol everywhere in the program, but what's the point with visibility keywords then? Walter, can you please finally fix this?
Feb 16 2006