www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Design Question: Why not access files without import?

reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
This is a question for Walter.  I'm curious about the reason why you 
have to import a file before using its functions and types.  Why can't 
you do this:
   int main() {
     std.stdio.printf("Hello world!\n");
     return 0;
   }

I'm thinking here is that the compiler could do this:
   * Search the current namespaces for 'std'
   * Not finding std, look for a directory std/ or a
     file std.d
   * Finding std/ but not std.d, look for a directory
     std/stdio/ or a file std/stdio.d
   * Finding std/stdio.d, it creates an implicit
     import, like this:

   /* implicit */ import std.stdio;
   int main() {
     std.stdio.printf("Hello world!\n");
     return 0;
   }

I'm guessing that there is some good reason for not doing this, but I'm 
curious what it is?
Aug 11 2004
next sibling parent reply kinghajj <kinghajj_member pathlink.com> writes:
In article <cfdp94$146p$1 digitaldaemon.com>, Russ Lewis says...
This is a question for Walter.  I'm curious about the reason why you 
have to import a file before using its functions and types.  Why can't 
you do this:
   int main() {
     std.stdio.printf("Hello world!\n");
     return 0;
   }

I'm thinking here is that the compiler could do this:
   * Search the current namespaces for 'std'
   * Not finding std, look for a directory std/ or a
     file std.d
   * Finding std/ but not std.d, look for a directory
     std/stdio/ or a file std/stdio.d
   * Finding std/stdio.d, it creates an implicit
     import, like this:

   /* implicit */ import std.stdio;
   int main() {
     std.stdio.printf("Hello world!\n");
     return 0;
   }

I'm guessing that there is some good reason for not doing this, but I'm 
curious what it is?

C#, you use imports so that you don't have to write "System.console.print" (I think that's it...), and can just write "print". I'd like to call functions without importing the modules, too, if that can be done.
Aug 11 2004
parent "Pablo Aguilar" <paguilarg hotmail.com> writes:
 I'm curious about that myself. If I'm not mistaken, that's how C# does it.

 C#, you use imports so that you don't have to write "System.console.print"

 think that's it...), and can just write "print". I'd like to call

 without importing the modules, too, if that can be done.

That's not quite right I think (please correct me if I'm wrong)... If you're talking about the "using namespace"s that's exactly how they work... however, you can't use a class/namespace if you don't have the assembly reference (and adding assembly references is just about what D's import does) Once you have the assembly reference, you can either type the full name "System.Console.print" or you can do type "using namespace System;" and from there on just type "Console.print" BTW, you can check out your .csproj file, and you'll see a <References> node in it, that's where the referred to assemblies are listed...
Aug 11 2004
prev sibling next sibling parent reply J C Calvarese <jcc7 cox.net> writes:
In article <cfdp94$146p$1 digitaldaemon.com>, Russ Lewis says...
This is a question for Walter.  I'm curious about the reason why you 
have to import a file before using its functions and types.  Why can't 
you do this:
   int main() {
     std.stdio.printf("Hello world!\n");
     return 0;
   }

I'm thinking here is that the compiler could do this:
   * Search the current namespaces for 'std'
   * Not finding std, look for a directory std/ or a
     file std.d
   * Finding std/ but not std.d, look for a directory
     std/stdio/ or a file std/stdio.d
   * Finding std/stdio.d, it creates an implicit
     import, like this:

   /* implicit */ import std.stdio;
   int main() {
     std.stdio.printf("Hello world!\n");
     return 0;
   }

I'm guessing that there is some good reason for not doing this, but I'm 
curious what it is?

That's an interesting idea. I don't know how difficult it would be for the compiler. It might be trickier than it seems. Even if it's easy for the compiler, I think there are reasons why the compiler shouldn't allow it. With auto-importing, we might run into a problem where we get more than we expected when we make a silly mistake. struct aStruct { int b; } aStruct moc; void main() { mod.b = 5; } It's a contrived example, but if you thought "mod" was an aStruct declared in that module (like moc), but there was a module with a variable called "b" in the same directory called "mod.d", you'd would get much different results than you expected. Sounds like things could get messy really quick if you re-use identifiers a lot. That reasoning is similar to why this isn't allowed: import std.c.*; Also, if you have the imports grouped near the top of the file it's easy to determine the dependencies of a particular module. jcc7
Aug 11 2004
parent reply "Filip Hanik - Dev" <devlists hanik.com> writes:
std.stdio.printf("Hello world!\n");

java allows this too, cause if you have the same class name in two different imported modules, how does the compiler resolve that today? Filip "J C Calvarese" <jcc7 cox.net> wrote in message news:cfdtrl$16mn$1 digitaldaemon.com...
 In article <cfdp94$146p$1 digitaldaemon.com>, Russ Lewis says...
This is a question for Walter.  I'm curious about the reason why you
have to import a file before using its functions and types.  Why can't
you do this:
   int main() {
     std.stdio.printf("Hello world!\n");
     return 0;
   }

I'm thinking here is that the compiler could do this:
   * Search the current namespaces for 'std'
   * Not finding std, look for a directory std/ or a
     file std.d
   * Finding std/ but not std.d, look for a directory
     std/stdio/ or a file std/stdio.d
   * Finding std/stdio.d, it creates an implicit
     import, like this:

   /* implicit */ import std.stdio;
   int main() {
     std.stdio.printf("Hello world!\n");
     return 0;
   }

I'm guessing that there is some good reason for not doing this, but I'm
curious what it is?

That's an interesting idea. I don't know how difficult it would be for the compiler. It might be

 than it seems. Even if it's easy for the compiler, I think there are

 the compiler shouldn't allow it.


 With auto-importing, we might run into a problem where we get more than we
 expected when we make a silly mistake.

 struct aStruct { int b; }
 aStruct moc;
 void main() { mod.b = 5; }

 It's a contrived example, but if you thought "mod" was an aStruct declared

 that module (like moc), but there was a module with a variable called "b"

 same directory called "mod.d", you'd would get much different results than

 expected. Sounds like things could get messy really quick if you re-use
 identifiers a lot.

 That reasoning is similar to why this isn't allowed:
 import std.c.*;


 Also, if you have the imports grouped near the top of the file it's easy

 determine the dependencies of a particular module.

 jcc7

Aug 11 2004
parent reply J C Calvarese <jcc7 cox.net> writes:
Filip Hanik - Dev wrote:
std.stdio.printf("Hello world!\n");

java allows this too, cause if you have the same class name in two different imported modules, how does the compiler resolve that today?

In D, you explicitly import both modules and append the module name when you use the function or class. For example... import std.string; import std.date; d_time d; int i; char[] dateStr; char[] intStr; void main() { dateStr = std.date.toString(d); intStr = std.string.toString(i); } The suggestion is that we should be able to leave out the explicit import statements at the top and have it still work. Does importing in Java work without explicit imports?
 
 Filip
 
 "J C Calvarese" <jcc7 cox.net> wrote in message
 news:cfdtrl$16mn$1 digitaldaemon.com...
 
In article <cfdp94$146p$1 digitaldaemon.com>, Russ Lewis says...

This is a question for Walter.  I'm curious about the reason why you
have to import a file before using its functions and types.  Why can't
you do this:
  int main() {
    std.stdio.printf("Hello world!\n");
    return 0;
  }

I'm thinking here is that the compiler could do this:
  * Search the current namespaces for 'std'
  * Not finding std, look for a directory std/ or a
    file std.d
  * Finding std/ but not std.d, look for a directory
    std/stdio/ or a file std/stdio.d
  * Finding std/stdio.d, it creates an implicit
    import, like this:

  /* implicit */ import std.stdio;
  int main() {
    std.stdio.printf("Hello world!\n");
    return 0;
  }

I'm guessing that there is some good reason for not doing this, but I'm
curious what it is?

That's an interesting idea. I don't know how difficult it would be for the compiler. It might be

trickier
than it seems. Even if it's easy for the compiler, I think there are

reasons why
the compiler shouldn't allow it.


With auto-importing, we might run into a problem where we get more than we
expected when we make a silly mistake.

struct aStruct { int b; }
aStruct moc;
void main() { mod.b = 5; }

It's a contrived example, but if you thought "mod" was an aStruct declared

in
that module (like moc), but there was a module with a variable called "b"

in the
same directory called "mod.d", you'd would get much different results than

you
expected. Sounds like things could get messy really quick if you re-use
identifiers a lot.

That reasoning is similar to why this isn't allowed:
import std.c.*;


Also, if you have the imports grouped near the top of the file it's easy

to
determine the dependencies of a particular module.

jcc7


-- Justin (a/k/a jcc7) http://jcc_7.tripod.com/d/
Aug 11 2004
parent reply "Sampsa Lehtonen" <snlehton cc.hut.fi> writes:
On Wed, 11 Aug 2004 17:48:24 -0500, J C Calvarese <jcc7 cox.net> wrote:

 Filip Hanik - Dev wrote:
 std.stdio.printf("Hello world!\n");

different imported modules, how does the compiler resolve that today?

In D, you explicitly import both modules and append the module name when you use the function or class. For example... import std.string; import std.date; d_time d; int i; char[] dateStr; char[] intStr; void main() { dateStr = std.date.toString(d); intStr = std.string.toString(i); } The suggestion is that we should be able to leave out the explicit import statements at the top and have it still work. Does importing in Java work without explicit imports?

Yes it does. I was wondering this same feature too. For example, in Java you can write something like: float x = my.pkg.Math.PI; without importing the Math class explicitely. The compiler uses same technique to solve the imports as the qualified names. When there is ambiquity, the compiler produces an error. In your example the std.date and std.string are necessary in front of the toString, because they have both same name. But in java you wouldn't need to import the date and string modules, since the qualified name already includes the package (implicit import). Actually, in Java you don't need to use imports at all, if you don't want to. -- Using Opera's revolutionary e-mail client: http://www.opera.com/m2/
Aug 12 2004
next sibling parent "Bent Rasmussen" <exo bent-rasmussen.info> writes:
 Actually, in Java you don't need to use imports at all, if you don't want
 to.

But you do! :-)
Aug 12 2004
prev sibling parent reply Arcane Jill <Arcane_member pathlink.com> writes:
Suppose we have:

#   ---- module silly.d ----
#   int a();
#   int b();
#   int c();
#   int d();
#   int e();
#   int f();
#   int g();
#   int h();
#   int i();
#   int j();
#   int k();
#   int l();
#   int m();
#   int n();
#   int o();
#   int p();
#   int q();
#   int r();
#   int s();
#   int t();
#   int u();
#   int v();
#   int w();
#   int x();
#   int y();
#   int z();

You want to call silly.f(), but ideally, you'd like to do it without polluting
your namespace with all those other functions. It looks like your only option is
to do:

#   import silly;

but that gets you a()..z(), not just f(). So now you have name-clashes all over
the place, which in turn means that you have to fully qualify loads of stuff
just to disambiguate.

People on this thread are suggesting that:

#    // no import
#    silly.f();

be more or less equivalent to

#    import silly;
#    silly.f();

but I think it should actually me more like:

#    import silly.f; // currently not legal D
#    silly.f();

This gets you:
(1) readable, unambiguous code (since silly.f() is fully qualified)
(2) an unpolluted namespace (since you haven't also pulled in a()..z()).

This would be very, very useful.

Oh - one last thing. import statements within libraries (and I include Phobos in
this) should, in general, be private imports, for a similar reason - to avoid
polluting the library-importer's namespace. For instance, currently, within the
std.stream source file, there is a line which reads:

#    import std.c.stdio;

I believe this should read

#    private import std.c.stdio;
#    ^^^^^^^

because I don't /want/ my namespace to be filled with all that C stdio junk,
just because I'm importing std.stream. If I choose to use it, I'll import it
explicitly. Ditto all other similar examples.

Arcane Jill
Aug 12 2004
parent reply Nick <Nick_member pathlink.com> writes:
In article <cffk4a$25cm$1 digitaldaemon.com>, Arcane Jill says...
Suppose we have:

#   ---- module silly.d ----

[snip]
#   import silly;

but that gets you a()..z(), not just f(). So now you have name-clashes all over
the place, which in turn means that you have to fully qualify loads of stuff
just to disambiguate.

There's an easy workaround for this, namely to enclose the imports in structs: # struct silly { import silly; } # ... # a(); // Doesn't work # silly.a(); // Works but some people might find this solution ugly. Nick
Aug 12 2004
parent reply ben 0x539.de writes:
In article <cfg3q0$2bp5$1 digitaldaemon.com>, Nick says...
There's an easy workaround for this, namely to enclose the imports in structs:

# struct silly { import silly; }
# ...
# a(); // Doesn't work
# silly.a(); // Works

but some people might find this solution ugly.

Perhaps we could have some syntax sugar for this. I could imagine an import like keyword, perhaps `` use silly; '' that would cause the compiler to scan silly.d and make its declarations available to the problem, yet would not bring them into the current namespace.
Aug 15 2004
parent reply Andy Friesen <andy ikagames.com> writes:
ben 0x539.de wrote:

 In article <cfg3q0$2bp5$1 digitaldaemon.com>, Nick says...
 
There's an easy workaround for this, namely to enclose the imports in structs:

# struct silly { import silly; }
# ...
# a(); // Doesn't work
# silly.a(); // Works

but some people might find this solution ugly.

Perhaps we could have some syntax sugar for this. I could imagine an import like keyword, perhaps `` use silly; '' that would cause the compiler to scan silly.d and make its declarations available to the problem, yet would not bring them into the current namespace.

Personally, I prefer this as the default behaviour. If I want to pull a bunch of stuff into the current namespace, I'd feel better if I could say so explicitly. Python's approach is exactly the same as D's, in fact, except for this key distinction. # must access contents with "foo.bar" qualifier # ie "foo.bar.baz()" import foo.bar # baz is pulled from foo.bar into the current scope # does not create foo.bar namespace at all. from foo.bar import baz # pull everything from foo.bar into the current scope from foo.bar import * -- andy
Aug 15 2004
next sibling parent ben 0x539.de writes:
In article <cfpini$1pgg$1 digitaldaemon.com>, Andy Friesen says...
ben 0x539.de wrote:

 In article <cfg3q0$2bp5$1 digitaldaemon.com>, Nick says...
 
There's an easy workaround for this, namely to enclose the imports in structs:

# struct silly { import silly; }
# ...
# a(); // Doesn't work
# silly.a(); // Works

but some people might find this solution ugly.

Perhaps we could have some syntax sugar for this. I could imagine an import like keyword, perhaps `` use silly; '' that would cause the compiler to scan silly.d and make its declarations available to the problem, yet would not bring them into the current namespace.

Personally, I prefer this as the default behaviour. If I want to pull a bunch of stuff into the current namespace, I'd feel better if I could say so explicitly.

Then just default yourself to use the `` use '' keyword or whatever syntax there will be, instead of always using import ;) I think the word import itself has the meaning of importing things into the current namespace, so I would expect it to behave exactly as it does now. But that does not mean that I agree that this should happen all the time. -- Benjamin Herr
Aug 15 2004
prev sibling parent reply Nick <Nick_member pathlink.com> writes:
In article <cfpini$1pgg$1 digitaldaemon.com>, Andy Friesen says...
Personally, I prefer this as the default behaviour.  If I want to pull a 
bunch of stuff into the current namespace, I'd feel better if I could 
say so explicitly.

I don't agree with this, at least not fully. One of the things that irritate me with C++ is having to type the "using namespace blah" even when there is absolutely no chance of a name conflict. I like the D way better, it only complains when there is reason to, and THEN you can explicitly import (through alias) the names you want. However I do agree that writing aliases can be tiresome if there are many names in conflict. The 'with' keyword exists to deal with this. But 'with' can currently only be used locally, not in the global scope. This could perhaps be changed, though. Example: there is a conflict between std.stream.st{in,out,err} and the C equivalents in std.c.stdio. The latter is unfortunately imported publically in std.stdio (that should also be changed IMO). This could be solved in the following way: # import std.stream; # import std.stdio; # # with(std.stream); // This doesn't currently work, but maybe it should? # # void main() # { # with(std.stream) // This already works # { # stdout.writeLine("foo"); # } # } What do you think, Walter? Nick
Aug 16 2004
next sibling parent reply ben 0x593.de writes:
In article <cfqf1m$2ej0$1 digitaldaemon.com>, Nick says...

I don't agree with this, at least not fully. One of the things that irritate me
with C++ is having to type the "using namespace blah" even when there is
absolutely no chance of a name conflict. I like the D way better, it only
complains when there is reason to, and THEN you can explicitly import (through
alias) the names you want.

You would still have that option with the way that was already proposed, so I do not see the point in your suggestion.
However I do agree that writing aliases can be tiresome if there are many names
in conflict. The 'with' keyword exists to deal with this. But 'with' can
currently only be used locally, not in the global scope. This could perhaps be
changed, though.

So you basically suggest the use of the with-qualifier as a better and more flexible syntax for `` using namespace ''? I still think that it would be easier to separate the operations of loading a module and bringing its identifiers into the current namespace.
What do you think, Walter?

I hope you forgive me for answering despite being Walter. - ben
Aug 16 2004
parent Nick <Nick_member pathlink.com> writes:
In article <cfqkra$2jf1$1 digitaldaemon.com>, ben 0x593.de says...
You would still have that option with the way that was already proposed, so I
do not see the point in your suggestion.

Ok I see you are correct, I guess I misread the original suggestion. I thought he was advocating a more C++ like syntax.
So you basically suggest the use of the with-qualifier as a better and more
flexible syntax for `` using namespace ''?

Using 'with' at least would not require inventing new keywords, and it would be consistant with the way it is already used.
I still think that it would be easier to separate the operations of loading a
module and bringing its identifiers into the current namespace.

Maybe, but I do not think it is critically important. Nick
Aug 16 2004
prev sibling parent Andy Friesen <andy ikagames.com> writes:
Nick wrote:
 In article <cfpini$1pgg$1 digitaldaemon.com>, Andy Friesen says...
 
Personally, I prefer this as the default behaviour.  If I want to pull a 
bunch of stuff into the current namespace, I'd feel better if I could 
say so explicitly.

I don't agree with this, at least not fully. One of the things that irritate me with C++ is having to type the "using namespace blah" even when there is absolutely no chance of a name conflict. I like the D way better, it only complains when there is reason to, and THEN you can explicitly import (through alias) the names you want. Example: there is a conflict between std.stream.st{in,out,err} and the C equivalents in std.c.stdio. The latter is unfortunately imported publically in std.stdio (that should also be changed IMO). This could be solved in the following way: # import std.stream; # import std.stdio; # # with(std.stream); // This doesn't currently work, but maybe it should? # # void main() # { # with(std.stream) // This already works # { # stdout.writeLine("foo"); # } # }

I think this is a bad idea because the 'with' keyword has a specific meaning associated with it: "with this stuff, do this stuff". As a statement all its own, it's just the first half of that idea. Readers will inevitably find themselves asking "do /what/ with it?". The Python style requires an extra keyword, but I think it's worth it. 'from' doesn't make for a very good identifier name anyway. (function names are almost always queries or verbs; attributes are nouns) -- andy
Aug 16 2004
prev sibling next sibling parent Andy Friesen <andy ikagames.com> writes:
Russ Lewis wrote:
 This is a question for Walter.  I'm curious about the reason why you 
 have to import a file before using its functions and types.  Why can't 
 you do this:
   int main() {
     std.stdio.printf("Hello world!\n");
     return 0;
   }
 
 I'm thinking here is that the compiler could do this:
   * Search the current namespaces for 'std'
   * Not finding std, look for a directory std/ or a
     file std.d
   * Finding std/ but not std.d, look for a directory
     std/stdio/ or a file std/stdio.d
   * Finding std/stdio.d, it creates an implicit
     import, like this:
 
   /* implicit */ import std.stdio;
   int main() {
     std.stdio.printf("Hello world!\n");
     return 0;
   }
 
 I'm guessing that there is some good reason for not doing this, but I'm 
 curious what it is?

This is more or less an artifact of the build system. In the C# world, everything is conceptually in one gigantic namespace, so all public symbols are available all the time. This is possible because the .NET build system completely internalizes the link phase. When the compiler is started, every source file and every external DLL is always specified on the spot. There is no way to do a partial rebuild. (nor is there much need for one: The C# compiler is almost as fast as DMD) DMD, being built to use the older OMF object format, is able to perform partial builds, but it doesn't necessarily have everything handed to it on the commandline. Therefore, it needs explicit directions to other source files. -- andy
Aug 11 2004
prev sibling next sibling parent "Walter" <newshound digitalmars.com> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:cfdp94$146p$1 digitaldaemon.com...
 This is a question for Walter.  I'm curious about the reason why you
 have to import a file before using its functions and types.  Why can't
 you do this:
    int main() {
      std.stdio.printf("Hello world!\n");
      return 0;
    }

 I'm thinking here is that the compiler could do this:
    * Search the current namespaces for 'std'
    * Not finding std, look for a directory std/ or a
      file std.d
    * Finding std/ but not std.d, look for a directory
      std/stdio/ or a file std/stdio.d
    * Finding std/stdio.d, it creates an implicit
      import, like this:

    /* implicit */ import std.stdio;
    int main() {
      std.stdio.printf("Hello world!\n");
      return 0;
    }

 I'm guessing that there is some good reason for not doing this, but I'm
 curious what it is?

Pretty much for the same reason the compiler doesn't automatically declare variables for you: int test(int hello) { return he11o + 1; } i.e. it makes for some really hard to find bugs.
Aug 11 2004
prev sibling parent Ilya Minkov <minkov cs.tum.edu> writes:
I guess this was done so that a simple build tool could identify all 
modules involved in the compilation by very simple scanning instead of 
complete parsing the source. There was such a tool, it even figured out 
libs needed and such. It is included with undig project on dsource, 
unfortunately it doesn't compile any longer

-eye

Russ Lewis schrieb:
 This is a question for Walter.  I'm curious about the reason why you 
 have to import a file before using its functions and types.  Why can't 
 you do this:
   int main() {
     std.stdio.printf("Hello world!\n");
     return 0;
   }
 
 I'm thinking here is that the compiler could do this:
   * Search the current namespaces for 'std'
   * Not finding std, look for a directory std/ or a
     file std.d
   * Finding std/ but not std.d, look for a directory
     std/stdio/ or a file std/stdio.d
   * Finding std/stdio.d, it creates an implicit
     import, like this:
 
   /* implicit */ import std.stdio;
   int main() {
     std.stdio.printf("Hello world!\n");
     return 0;
   }
 
 I'm guessing that there is some good reason for not doing this, but I'm 
 curious what it is?
 

Aug 12 2004