www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Proposal: "import thing;" checks for thing/thing.d before it tries

reply Don Clugston <dac nospam.com.au> writes:
A recent post by Alan West contained an idea which I think is worthy of 
further consideration. I've probably distorted it beyond recognition, 
though :-)

EXISTING BEHAVIOUR

import outer.inner;

looks for the file "outer/inner.d", and henceforth outer.inner can only 
refer to that file.

But,

import outer.inner.thing;

looks for the file "outer/inner/thing.d" and henceforth, outer.inner can 
only refer to the directory.
If outer contains both inner/thing.d and inner.d, either of those above 
two lines will compile, but if both are used, compilation will fail. 
This behaviour is undesirable. When used together, either both should 
work, or both should fail.

However, if something like this worked, there would be some appealing 
consequences, as discussed below.

PROPOSAL  - Somewhat analagous to implicit template properties.

It is an error to refer to "outer.inner" in any form, if both 
outer/inner.d and outer/inner/ exist.

import outer.inner;

would be resolved as follows.
Does outer/inner exist?
CASE A: YES -> ASSERT(outer.inner.d does not exist)
        The required module is "outer/inner/inner.d".
CASE B: NO -> The required module is "outer/inner.d"

More generally,
p.q.r.s
refers to either "p/q/r/s/s.d" or "p/q/r/s.d" depending on whether the 
last element exists as a directory, or not.

Internally, the compiler would use the fully qualified name, 
("p/q/r/s/s"), but could collapse them ("p/q/r/s") when any kind of IO 
is required, eg error messages.

An often requested feature is the Java-style

import somepackage.*;

but this is unsafe, because the meaning of the program could change if 
another file were added to the somepackage directory, making it 
impossible for the author of 'somepackage' to safely extend the library.
With this proposal, the author could provide somepackage/somepackage.d
which would allow the exceedingly simple:

import somepackage;

Now you could follow Derek's suggestion and provide somepackage/all.d, 
but that has the consequence that later on, somepackage.all might not 
really be "all"! (it would just be "all" the version 1.0 files).

That's just syntactic sugar, and not very compelling. But more 
interesting to me, is that it would allow an existing file to be turned 
into a directory. There are two cases in Phobos where this would be very 
useful:

std/math.d

could be changed into std/math/math.d, std/math/statistic.d, 
std/math/discrete.d,...

and existing code that used

import std.math;

would continue to work correctly, yet we could also write
import std.math.statistic;
to import functions from mathematical statistics.

Another case where this would be useful is in
std.c.windows.windows

import std.c.windows;
would just import the windows.d header file, but
import std.c.windows.directx;
would import the DirectX headers. Subsequently, there might
be be optional parts of DirectX, so that could also become a directory,
with a directx.d file retained for backwards compatibility.

Since there are no header files in D, IMHO it's important to have 
mechanism for reducing file size. There is a problem in std.math.d; it 
is much too big. The problem has been concealed somewhat by moving most 
of the implementation into C functions; but that's not a general solution.

I believe that this situation is quite common, and arises whenever a 
module expands more than originally expected. This proposal would give a 
library maintainer considerable flexibility.
Nov 28 2005
next sibling parent Bruno Medeiros <daiphoenixNO SPAMlycos.com> writes:
Don Clugston wrote:
 A recent post by Alan West contained an idea which I think is worthy of 
 further consideration. I've probably distorted it beyond recognition, 
 though :-)
 
 EXISTING BEHAVIOUR
 
 import outer.inner;
 
 looks for the file "outer/inner.d", and henceforth outer.inner can only 
 refer to that file.
 
 But,
 
 import outer.inner.thing;
 
 looks for the file "outer/inner/thing.d" and henceforth, outer.inner can 
 only refer to the directory.
 If outer contains both inner/thing.d and inner.d, either of those above 
 two lines will compile, but if both are used, compilation will fail. 
 This behaviour is undesirable. When used together, either both should 
 work, or both should fail.
 
 However, if something like this worked, there would be some appealing 
 consequences, as discussed below.
 
 PROPOSAL  - Somewhat analagous to implicit template properties.
 
 It is an error to refer to "outer.inner" in any form, if both 
 outer/inner.d and outer/inner/ exist.
 
 import outer.inner;
 
 would be resolved as follows.
 Does outer/inner exist?
 CASE A: YES -> ASSERT(outer.inner.d does not exist)
        The required module is "outer/inner/inner.d".
 CASE B: NO -> The required module is "outer/inner.d"
 
 More generally,
 p.q.r.s
 refers to either "p/q/r/s/s.d" or "p/q/r/s.d" depending on whether the 
 last element exists as a directory, or not.
 
 Internally, the compiler would use the fully qualified name, 
 ("p/q/r/s/s"), but could collapse them ("p/q/r/s") when any kind of IO 
 is required, eg error messages.
 
 An often requested feature is the Java-style
 
 import somepackage.*;
 
 but this is unsafe, because the meaning of the program could change if 
 another file were added to the somepackage directory, making it 
 impossible for the author of 'somepackage' to safely extend the library.
 With this proposal, the author could provide somepackage/somepackage.d
 which would allow the exceedingly simple:
 
 import somepackage;
 
 Now you could follow Derek's suggestion and provide somepackage/all.d, 
 but that has the consequence that later on, somepackage.all might not 
 really be "all"! (it would just be "all" the version 1.0 files).
 

Hum...
 That's just syntactic sugar, and not very compelling. But more 
 interesting to me, is that it would allow an existing file to be turned 
 into a directory. There are two cases in Phobos where this would be very 
 useful:
 
 std/math.d
 
 could be changed into std/math/math.d, std/math/statistic.d, 
 std/math/discrete.d,...
 
 and existing code that used
 
 import std.math;
 
 would continue to work correctly, yet we could also write
 import std.math.statistic;
 to import functions from mathematical statistics.
 

Another possible solution would be to simply allow a package to have te same name as a module. Wouldn't cause any language problems that I can see, but it would be a significant core change, as the structured module system would now be more akin to namespaces (the fundamental difference, for those who are not clear, is that a namespace-like module can contain other modules/namespaces). It would be, however, a weird namespace system, because of the module to file/directory correspondences. Or another possible (also big-change) solution would be to adopt a conventional namespace system (like C++, C#). I'm not actually sugesting this change, I'm just saying it. This bordelines one a more general issue I've brought up before, the D structured naming system (see http://www.digitalmars.com/d/archives/digitalmars/D/28423.html ) , and altough I *know* the current D status is ... well, _broken_ (or misguided, I can't find the right word), I'm not sure what would be the best way for this whole thing to work. (altough I'm clear on how certain aspects should be, some on them are mentioned on that thread) -- Bruno Medeiros - CS/E student "Certain aspects of D are a pathway to many abilities some consider to be... unnatural."
Nov 29 2005
prev sibling parent Georg Wrede <georg.wrede nospam.org> writes:
Don Clugston wrote:
 A recent post by Alan West contained an idea which I think is worthy
 of further consideration. I've probably distorted it beyond
 recognition, though :-)
 
 EXISTING BEHAVIOUR
 
 import outer.inner;
 
 looks for the file "outer/inner.d", and henceforth outer.inner can
 only refer to that file.
 
 But,
 
 import outer.inner.thing;
 
 looks for the file "outer/inner/thing.d" and henceforth, outer.inner
 can only refer to the directory. If outer contains both inner/thing.d
 and inner.d, either of those above two lines will compile, but if
 both are used, compilation will fail. This behaviour is undesirable.
 When used together, either both should work, or both should fail.
 
 However, if something like this worked, there would be some appealing
  consequences, as discussed below.
 
 PROPOSAL  - Somewhat analagous to implicit template properties.
 
 It is an error to refer to "outer.inner" in any form, if both 
 outer/inner.d and outer/inner/ exist.
 
 import outer.inner;
 
 would be resolved as follows. Does outer/inner exist? CASE A: YES ->
 ASSERT(outer.inner.d does not exist) The required module is
 "outer/inner/inner.d". CASE B: NO -> The required module is
 "outer/inner.d"
 
 More generally, p.q.r.s refers to either "p/q/r/s/s.d" or "p/q/r/s.d"
 depending on whether the last element exists as a directory, or not.
 
 Internally, the compiler would use the fully qualified name, 
 ("p/q/r/s/s"), but could collapse them ("p/q/r/s") when any kind of
 IO is required, eg error messages.
 
 An often requested feature is the Java-style
 
 import somepackage.*;
 
 but this is unsafe, because the meaning of the program could change
 if another file were added to the somepackage directory, making it 
 impossible for the author of 'somepackage' to safely extend the
 library. With this proposal, the author could provide
 somepackage/somepackage.d which would allow the exceedingly simple:
 
 import somepackage;
 
 Now you could follow Derek's suggestion and provide
 somepackage/all.d, but that has the consequence that later on,
 somepackage.all might not really be "all"! (it would just be "all"
 the version 1.0 files).
 
 That's just syntactic sugar, and not very compelling. But more 
 interesting to me, is that it would allow an existing file to be
 turned into a directory. There are two cases in Phobos where this
 would be very useful:
 
 std/math.d
 
 could be changed into std/math/math.d, std/math/statistic.d, 
 std/math/discrete.d,...
 
 and existing code that used
 
 import std.math;
 
 would continue to work correctly, yet we could also write import
 std.math.statistic; to import functions from mathematical statistics.

Now, this is the first Deep thing about imports I've seen. Once one understands this proposal, it gets very hard to accept the other proposed alternatives.
 Another case where this would be useful is in std.c.windows.windows
 
 import std.c.windows; would just import the windows.d header file,
 but import std.c.windows.directx; would import the DirectX headers.
 Subsequently, there might be be optional parts of DirectX, so that
 could also become a directory, with a directx.d file retained for
 backwards compatibility.
 
 Since there are no header files in D, IMHO it's important to have 
 mechanism for reducing file size. There is a problem in std.math.d;
 it is much too big. The problem has been concealed somewhat by moving
 most of the implementation into C functions; but that's not a general
 solution.
 
 I believe that this situation is quite common, and arises whenever a
  module expands more than originally expected. This proposal would
 give a library maintainer considerable flexibility.

Nov 29 2005