Bug 3603 – Allow selective import syntax to import several modules from a package
Status
RESOLVED
Resolution
INVALID
Severity
enhancement
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
Linux
Creation time
2009-12-08T13:49:19Z
Last change time
2022-07-18T18:48:26Z
Assigned to
No Owner
Creator
Leandro Lucarella
Comments
Comment #0 by leandro.lucarella — 2009-12-08T13:49:19Z
Importing a lot of stuff from a deeply nested modules is very annoying because it needs a lot of repeating, for example:
import really.very.deeply.nested.package.module1;
import really.very.deeply.nested.package.module2;
import really.very.deeply.nested.package.module3;
Allowing selective import syntax to do this in a more concise way would be a great improvement over this, the above example could be rewritten as:
import really.very.deeply.nested.package: module1, module2, module3;
Maybe this should be semantically equivalent to this instead of the first example:
import module1 = really.very.deeply.nested.package;
import module2 = really.very.deeply.nested.package;
import module3 = really.very.deeply.nested.package;
It can be a little more consistent with selective imports. But we still have to same problem if we don't want to type module1.symbol and want to type just symbol instead.
Maybe a new syntax can be introduced to allow that, like:
import really.very.deeply.nested.package { module1, module2, module3 };
Or something similar.
Comment #1 by turkeyman — 2012-10-15T06:38:05Z
Massive +1 from me! (only 3 years later)
Comment #2 by nick — 2013-01-23T08:55:04Z
> import really.very.deeply.nested.package: module1, module2, module3;
I think this is the way to go, and is very commonly useful.
> import really.very.deeply.nested.package { module1, module2, module3 };
I don't think it's worth allowing both selective modules and selective symbols in the same statement. Importing selective symbols from a module can just use a separate statement, and it's less common than full module imports anyway.
Comment #3 by bearophile_hugs — 2013-01-24T18:17:12Z
I'd like to write:
import std: stdio, algorithm, range, array;
Comment #4 by john.michael.hall — 2017-08-16T23:31:23Z
Multiple named imports also discussed here:
https://forum.dlang.org/thread/[email protected]
------------------------------------
With respect to:
> import really.very.deeply.nested.package: module1, module2, module3;
or
> import std: stdio, algorithm, range, array;
consider:
-----[ foo\package.d ]-----
module foo;
public import foo.bar;
public import foo.baz;
public import foo.bazinga;
-----[ foo\bar.d ]-----
module foo.bar;
void bar() { };
-----[ foo\baz.d ]-----
module foo.baz;
void baz() { };
-----[ foo\bazinga.d ]-----
module foo.bazinga;
void bazinga() { };
------------------------------------
Under your suggestion, if you:
import foo : bar, baz;
how does the compiler know to import the functions or the modules? Under the current approach, it's not an issue since the selective import only brings in the symbols.
------------------------------------
I think the alternative would be to introduce a new syntax for selective module imports, where
import foo :: bar, baz;
causes the modules bar and baz to be imported, but not bazinga. This would be equivalent to
import foo.bar;
import foo.baz;
Static imports should follow a similar pattern.
It gets a little more complicated with re-named imports where something like
import barbaz = foo :: bar, baz;
may be possible. This functionality currently requires a more challenging workaround, discussed in the above thread, as it is an error to write
import barbaz = foo.bar;
import barbaz = foo.baz;
because barbaz is assigned to two things.
This functionality may also mix with the current functionality for selective imports, such as
import foo :: bar, baz : bar, baz;
though this depends on the implementation details, for instance, the following would not compile
import foo.bar : bar, baz;
import foo.baz : bar, baz;
so the compiler would need to do something like search foo.bar for either bar or baz and only import them if they are there, cross off what is found, then search foo.baz for the remainder, and give an error if something isn't found.
In addition, one could have a re-named version
import barbaz = foo :: bar, baz : bar, baz;
which should follow from getting the above to work.
Finally, one point I didn't address specifically was about the deeply nested modules that the OP refers to. The OPs example of
> import really.very.deeply.nested.package: module1, module2, module3;
would become
> import really.very.deeply.nested.package :: module1, module2, module3;
However, it also would be convenient to be able to write
> import really :: module1, module2, module3;
assuming the module names are unique. I am not sure if this is possible.
Comment #5 by nick — 2019-01-06T14:32:25Z
(In reply to John Hall from comment #4)
> import foo : bar, baz;
>
> how does the compiler know to import the functions or the modules?
It could work:
1. If foo is a file called foo.d, it's a module import with selective symbols.
2. If a directory foo/ exists as well, the compiler could show a warning.
3. If foo is not a file but a directory, it's a package import with selective *modules*.
Although when searching multiple import paths given on the command-line it could get confusing with conflicts.
> import foo :: bar, baz;
That is clearer syntax and simplifies the feature design, but it seems a bit inconsistent with fully qualified symbols in code, which use `package1.module1`, not `package1::module1` (the latter would arguably be better for FQNs but I doubt it will be added now). `import package foo : bar, baz;` syntax is another option, and is intuitive.
This Phobos file is a good example case for this feature:
https://github.com/dlang/phobos/blob/master/std/experimental/allocator/building_blocks/package.d#L306
In fact, I think a single package import with selective modules could also support selectively importing a single symbol from each module (which is a common case for library code):
import mod : sym1, sym2; // selective symbols from a single module
import package pack : mod1, mod2, mod3; // selective modules from a single package
import package pack : mod1, mod2 : sym, mod3 : sym; // selective modules plus optional single selective symbol per module
For multiple selective symbols per module, this is not possible with this syntax, use a separate import statement per module. This is a better design IMO than allowing arbitrary `{mod1, mod2 : {sym1, sym2}, mod3 : {sym1, sym2}}` code because it forces better readability.
The grammar (ignoring renaming) would be something like:
ImportDeclaration:
...
import ModuleIdentifier : SymbolImportList;
import package PackageIdentifier : ModuleImportList;
ModuleImportList:
ModuleIdentifier
ModuleIdentifier : SymbolIdentifier
ModuleIdentifier, ModuleImportList
ModuleIdentifier : SymbolIdentifier, ModuleImportList
Comment #6 by greeenify — 2019-01-08T04:18:53Z
Fwiw this change would require a DIP as the last time we tried to just slightly change the import syntax, there was an outcry and a subsequent revert.
Comment #7 by razvan.nitu1305 — 2019-10-24T12:17:15Z
(In reply to Leandro Lucarella from comment #0)
> Importing a lot of stuff from a deeply nested modules is very annoying
> because it needs a lot of repeating, for example:
>
> import really.very.deeply.nested.package.module1;
> import really.very.deeply.nested.package.module2;
> import really.very.deeply.nested.package.module3;
>
> Allowing selective import syntax to do this in a more concise way would be a
> great improvement over this, the above example could be rewritten as:
>
> import really.very.deeply.nested.package: module1, module2, module3;
>
> Maybe this should be semantically equivalent to this instead of the first
> example:
>
> import module1 = really.very.deeply.nested.package;
> import module2 = really.very.deeply.nested.package;
> import module3 = really.very.deeply.nested.package;
>
> It can be a little more consistent with selective imports. But we still have
> to same problem if we don't want to type module1.symbol and want to type
> just symbol instead.
>
> Maybe a new syntax can be introduced to allow that, like:
> import really.very.deeply.nested.package { module1, module2, module3 };
>
> Or something similar.
This can be trivially solved by:
import really;
Closing as INVALID
Comment #8 by nick — 2019-10-26T10:32:51Z
> import really;
No, that imports many symbols the user doesn't want in scope. Phobos has a policy of importing the tightest possible module name with selective imports so code doesn't break when symbols are added to modules that aren't even needed.
Comment #9 by john.michael.hall — 2022-07-18T18:48:26Z
Looks like this was closed again as Invalid.
In addition to the previous argument that `import really;` brings in more symbols than needed, it also only works if the user creates the public imports that enable it to work.
Another approach that I think would work well would be to expand the with statement to work with modules. That implies that this:
with(std) import stdio, math;
would be equivalent with
import std.stdio, std.math;
It still doesn't have all the functionality discussed above, but I think it addresses the original point.