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.
--John
Sounds 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









Lars Ivar Igesund <larsivar igesund.net> 