Jump to page: 1 2
Thread overview
Some (big) problems with modules right now (long post)
Jan 24, 2005
Walter
Jan 25, 2005
Walter
Jan 26, 2005
Walter
Jan 29, 2005
Walter
Jan 24, 2005
Ben Hinkle
Re: Some (big) problems with modules right now : frontend question
Jan 24, 2005
Charles
Jan 24, 2005
Ben Hinkle
Jan 25, 2005
Charlie
Jan 24, 2005
Georg Wrede
Jan 24, 2005
Ben Hinkle
Jan 24, 2005
Regan Heath
Feb 16, 2005
Derek Parnell
January 24, 2005
Working on a large(r) project in D, I've started to notice some.. irritation and clumsiness with modules.  The spec for modules is not very extensive, either.  So for the past day or so, I've been working on figuring out just how the modules work (or don't).  Here are the problems I've come across.



Naming



The name deduction process for modules seems to go like this, as defined in the spec:

            if file has a "module" declaration

            {

                        use "module" declaration name

            }

            else

            {

                        ambiguous?  spec says:

                                    "the module name is taken to be the same name (stripped of path                                               and extension)"

                        and at the same time:

                                    "The packages correspond to directory names in the source file                                                 path."

            }



This can be confusing.  I could have a module with a filename of /modules/math/vector.d, but have a module declaration in the file that calls it "3dmath.vectors" or something.  I understand why this is necessary - some file systems are case-sensitive, and it'd be a pain to have different cases for the directory name and the "module" name (and in fact, there may be computers which don't have the concept of directories, making the directory system worthless there).



Perhaps the directory system should be removed, if for nothing else but consistency.  That is, all modules must have a module declaration for them to be importable.  This would still allow modules to be named differently from their directories, but it'd be consistent - you'd have to look in a module to see what it's called.  No more guessing whether to call it by its directory name or its "module" name.



Lastly, the directory naming ambiguity is described in the next section..



Importing



I've come across two rather confusing errors with this naming stuff as well as some other.. issues.  My directory tree looks like this:



/dtest

+---dtest.d

+---/mod

+---+---mod1.d



The contents of the files:



dtest.d



import std.stdio;

import mod1;



void main()

{
     writefln(x);

}



mod1.d



int x=5;



This compiles and runs.  I'm kind of confused why it doesn't require me to write import mod.mod1;, as it should be using the directory naming system (and no, /dtest/mod is not in my include path).  In fact, I can nest the mod1.d in as many layers of directories as I want and I'll still be able to import it as just mod1.



In fact, if I try to use import mod.mod1, I get the following, confusing error:

dtest.d(2): module mod1 is in multiply defined

What on earth is that supposed to mean?  Is the "in" just a typo?  If so, where is the module multiply defined?  Why can't I import the module like this, if the directory structure is like so?



If, however, I remove mod1.d from the compiler command line, I must use import mod.mod1.  Of course, the linker then complains about x being an unresolved reference.  Why are there two systems of import naming depending on whether or not I'm compiling the module?  Yet another reason to question the directory naming system.



Even stranger: if I change my import to import mod.mod1, and add a module declaration to the module called module mod1, I get yet another incomprehensible error:

dtest.d(2): module mod1 is in multiple packages mod1

If I use import mod1, on the other hand, it works fine.



And yet again, if the module is not being compiled, I must explicitly qualify the module name as mod.mod1.



Oh, and this one takes the cake:



dtest.d

import std.stdio;

// notice what I call it here!

import mod.mod1;



void main()

{

     writefln(x);

}



mod1.d

// notice the name is now mod2!

module mod2;

int x=5;



This compiles and runs when mod1 is not being compiled.  The linker whines of course.  Apparently, the "module" declaration is completely ignored if the module is just being lexed!  If I compile the module as well, I must import mod2, not mod.mod1 in dtest.d.  Very confusing.



Then you start getting into multiple modules and modules which import one another.  Consider that there is a mod2.d, which does something else, who cares what.  Say mod1 privately imports mod2.  When all three files are compiled, the modules can be imported just by their name.  However, take the modules out of the command line, and suddenly, mod1 can't import mod2 by just name anymore!  You have to actually modify mod1 by changing the import mod2 to import mod.mod2!  How is that easy to use?



Protection Attributes



By default, everything is public, and that works fine.  Then there are package and private.



Package, to put it simply, doesn't seem to do ANYTHING.  I've tried putting modules in so many different directory trees, naming them different ways, compiling them or not, etc.  And I can still, very easily, import a module and access its package members.  Perhaps it has something to do with the module's namespace being merged with the current namespace when it is imported?  I can't seem to figure it out.



Private works fine for variables, arrays, and functions, but beyond that, it does nothing.  Enums, structs, interfaces, unions, and classes can all be declared private, but it doesn't stop you from using them outside the module.  Note that it's just definitions that don't work.  if I do this in the module:



private class C
{
     int x;
}



C c;



I will be able to create Cs outside the module, access C's public static members etc.  But I will not be allowed to access the instance "c."



I posted this as a possible bug, and someone said that perhaps it's just making the definition private.  Well what good does that do?  It's not like we can modify the definition outside of the file, and it would make more sense and be more useful if the entire class were inaccessible outside the module.  The same applies for structs, interfaces, unions, and enums.



Conclusion



I really think this mess needs to be cleaned up before 1.0.  Modules seem to be a convenient way to organize your code, but I swear, there are just as many caveats and irritation as using a header/cpp pair in C++.


January 24, 2005
On your first example -

o Please turn off html in your message format. html not only makes it difficult to embed replies to your long message, I (and many others) have html turned off in my newsreader as it is a security risk. Please use plaintext only.

o Please, for your first example, show exactly which directories dtest.d and mod1.d are in (I am not positive what is meant by +----+----mod1.d), what directory was the default when you ran the compiler, and what -I switches were used to compile. All of these have a large influence over the results.


January 24, 2005
> o Please turn off html in your message format. html not only makes it difficult to embed replies to your long message, I (and many others) have html turned off in my newsreader as it is a security risk. Please use plaintext only.

Yes, Sahib ;)

> o Please, for your first example, show exactly which directories dtest.d
and
> mod1.d are in (I am not positive what is meant by +----+----mod1.d), what directory was the default when you ran the compiler, and what -I switches were used to compile. All of these have a large influence over the
results.

/dtest/dtest.d
/dtest/mod/mod1.d

I was trying to do some kind of ASCII representation of the directory structure, but I guess it didn't work out.  All subsequent examples use the same directory structure (and mod2.d is in /dtest/mod as well).

The default directory is /dtest.

The only -I switch in effect is the phobos include path (/dmd/src/phobos).


January 24, 2005
> "Jarrett Billingsley" <kb3ctd2@yahoo.com> wrote in message
news:ct39ut$1kqi$1@digitaldaemon.com...
[snip]
> Conclusion
>
> I really think this mess needs to be cleaned up before 1.0.  Modules seem
to be a convenient way to organize your code, but I swear, there  are just as many caveats and irritation as using a header/cpp pair in C++.

I think the module/package/import system is pretty much like Java's (and I assume C#'s). One difference is that files without a module declaration are given a module name while in Java there is no default mechanism. There probably are a few other differences but not much I think. Maybe some better error messages would make it easier to use.


January 24, 2005
> One difference is that files without a module declaration are given a module name while in Java there is no default mechanism

Question about the frontend :

When there is no module declaration present, the toChars() method of Module
returns garbage , strlen and strcmp dont work on it , so how can I know when
a  ( Module ) has no declared 'module foo;' ?  ( Module->ident->toChars()
not working either )

Thx,
C


"Ben Hinkle" <bhinkle@mathworks.com> wrote in message news:ct3eq5$1rqv$1@digitaldaemon.com...
>
> > "Jarrett Billingsley" <kb3ctd2@yahoo.com> wrote in message
> news:ct39ut$1kqi$1@digitaldaemon.com...
> [snip]
> > Conclusion
> >
> > I really think this mess needs to be cleaned up before 1.0.  Modules
seem
> to be a convenient way to organize your code, but I swear, there  are just as many caveats and irritation as using a header/cpp pair in C++.
>
> I think the module/package/import system is pretty much like Java's (and I assume C#'s). One difference is that files without a module declaration
are
> given a module name while in Java there is no default mechanism. There probably are a few other differences but not much I think. Maybe some
better
> error messages would make it easier to use.
>
>





January 24, 2005
"Charles" <no@email.com> wrote in message news:ct3fo6$1t4s$1@digitaldaemon.com...
> > One difference is that files without a module declaration are given a module name while in Java there is no default mechanism
>
> Question about the frontend :
>
> When there is no module declaration present, the toChars() method of
Module
> returns garbage , strlen and strcmp dont work on it , so how can I know
when
> a  ( Module ) has no declared 'module foo;' ?  ( Module->ident->toChars()
> not working either )
>
> Thx,
> C

It looks like the module declaration is used at line 393 of module.c in the frontend source. After parsing the module if there is a ModuleDeclaration then it uses the name from that instead of the file name. I'm not sure if this helps answer your question but I'd poke around there.

As a side note the typo in the "is in multiply defined" error Jarrett was referring to is on line 416 of module.c

-Ben


January 24, 2005
>>I really think this mess needs to be cleaned up before 1.0.  Modules seem
> 
> to be a convenient way to organize your code, but I swear, there  are just
> as many caveats and irritation as using a header/cpp pair in C++.
> 
> I think the module/package/import system is pretty much like Java's (and I
> assume C#'s). One difference is that files without a module declaration are
> given a module name while in Java there is no default mechanism. There
> probably are a few other differences but not much I think. Maybe some better
> error messages would make it easier to use.

[removed the names above, since I'm not directing this to them...]

Whether the "module/package/import system" is like that of Java or not is not the issue here. What counts is the end result. If a smart programmer new to the language can't figure it out easily, by just trying out a few examples (I know, "don't ask the compiler, check the specs!", but, hey, we live in the real world), then the system is unobvious. This should be remedied.
January 24, 2005
"Georg Wrede" <georg.wrede@nospam.org> wrote in message news:41F54AFD.4020702@nospam.org...
> >>I really think this mess needs to be cleaned up before 1.0.  Modules
seem
> >
> > to be a convenient way to organize your code, but I swear, there  are
just
> > as many caveats and irritation as using a header/cpp pair in C++.
> >
> > I think the module/package/import system is pretty much like Java's (and
I
> > assume C#'s). One difference is that files without a module declaration
are
> > given a module name while in Java there is no default mechanism. There probably are a few other differences but not much I think. Maybe some
better
> > error messages would make it easier to use.
>
> [removed the names above, since I'm not directing this to them...]
>
> Whether the "module/package/import system" is like that of Java or not is not the issue here. What counts is the end result.

I agree. I mentioned Java to point out another fairly successful system that used a similar mechanism. Compared to C++'s #define mechanism D's imports might seem wierd but compared to Java's import it seems very natural.

> If a smart
> programmer new to the language can't figure it out easily, by just
> trying out a few examples (I know, "don't ask the compiler, check the
> specs!", but, hey, we live in the real world), then the system is
> unobvious. This should be remedied.

Yup, agreed. I think better error messages and perhaps more doc would help since the relation between module declaration and the actual directory structure and file names is not clear. And I agree with the OP's point about "private class" declarations not doing anything when they probably should. But I'm not so quick to agree that the module and import behavior needs fundamental changes or is a mess.


January 24, 2005
On Mon, 24 Jan 2005 14:57:02 -0500, Ben Hinkle <bhinkle@mathworks.com> wrote:

<snip>

> And I agree with the OP's point about "private class" declarations not doing anything when they probably should.

<snip>

To make a class private I have always done:

# class A {
# 	private this() {
# 	}
# }

It seems to me that:

# private class A {
# 	this() {
# 	}
# }

doesn't do anything at the moment, I couldn't even get it to deny me access to an instance as the OP did.

So, my vote would be that "private class X" means the definition/declaration of class X is private, meaning it behaves as private instances do.

Regan
January 25, 2005
"Jarrett Billingsley" <kb3ctd2@yahoo.com> wrote in message news:ct3eic$1rhu$1@digitaldaemon.com...
> /dtest/dtest.d
> /dtest/mod/mod1.d
>
> I was trying to do some kind of ASCII representation of the directory structure, but I guess it didn't work out.  All subsequent examples use
the
> same directory structure (and mod2.d is in /dtest/mod as well).
>
> The default directory is /dtest.
>
> The only -I switch in effect is the phobos include path (/dmd/src/phobos).

I can't reproduce the difficulty you're having with it. Here's what I have, which gives the expected error:

---------------------------------------------------
C:\dtest>type dtest.d
import std.stdio;
import mod1;

void main()
{
     writefln(x);
}

C:\dtest>type mod\mod1.d
int x = 5;

C:\dtest>dir
 Volume in drive C has no label.
 Volume Serial Number is C83C-5D49

 Directory of C:\dtest

01/25/2005  12:27 AM    <DIR>          mod
01/25/2005  12:28 AM                73 dtest.d
01/25/2005  12:28 AM    <DIR>          ..
01/25/2005  12:28 AM    <DIR>          .
               1 File(s)             73 bytes
               3 Dir(s)  10,404,511,744 bytes free

C:\dtest>dir mod
 Volume in drive C has no label.
 Volume Serial Number is C83C-5D49

 Directory of C:\dtest\mod

01/25/2005  12:27 AM    <DIR>          ..
01/25/2005  12:27 AM                12 mod1.d
01/25/2005  12:27 AM    <DIR>          .
               1 File(s)             12 bytes
               2 Dir(s)  10,404,511,744 bytes free

C:\dtest>dmd dtest
Error: Error reading file 'mod1.d'


C:\dtest>
------------------------------------------


« First   ‹ Prev
1 2