Bug 2179 – [module] import inside class works but is not in spec
Status
RESOLVED
Resolution
WORKSFORME
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D1 (retired)
Platform
x86
OS
Windows
Creation time
2008-06-26T13:52:00Z
Last change time
2014-02-24T15:33:05Z
Keywords
spec
Assigned to
nobody
Creator
wbaxter
Comments
Comment #0 by wbaxter — 2008-06-26T13:52:14Z
DMD accepts imports placed inside of class scopes. This is useful for template mixins because it means you can put the imports needed by the mixin into the template itself.
However it doesn't seem to be allowed by the grammar in the spec. It is useful, and it works, and therefore I think the grammar should be updated to reflect this.
Here's the test case:
----
module miximport;
import std.stdio;
class Foo {
import miximport_imp;
this() {
writefln("Hi there from Inner - magic value: %s", magic_value);
}
}
void main() { new Foo; }
----
Running dmd -v gives this, which includes miximport_imp in the list of imports:
----
F:\bax\Code\d\play>dmd -v miximport.d
parse miximport
semantic miximport
import object (f:\usr\pkg\d\dmd\bin\..\import\tango\object.di)
import std.stdio (f:\usr\pkg\d\dmd\bin\..\import\tangobos\std\stdio.d)
import std.compat (f:\usr\pkg\d\dmd\bin\..\import\tangobos\std\compat.d)
import tango.stdc.stdio (f:\usr\pkg\d\dmd\bin\..\import\tango\tango\stdc\stdio.d)
import tango.stdc.stdarg (f:\usr\pkg\d\dmd\bin\..\import\tango\tango\stdc\stdarg.d)
import tango.stdc.stddef (f:\usr\pkg\d\dmd\bin\..\import\tango\tango\stdc\stddef.d)
import tango.stdc.config (f:\usr\pkg\d\dmd\bin\..\import\tango\tango\stdc\config.d)
import std.c.stdio (f:\usr\pkg\d\dmd\bin\..\import\tangobos\std\c\stdio.d)
import std.format (f:\usr\pkg\d\dmd\bin\..\import\tangobos\std\format.d)
import std.stdarg (f:\usr\pkg\d\dmd\bin\..\import\tangobos\std\stdarg.d)
import tango.core.Vararg (f:\usr\pkg\d\dmd\bin\..\import\tango\tango\core\Vararg.d)
import std.c.stdarg (f:\usr\pkg\d\dmd\bin\..\import\tangobos\std\c\stdarg.d)
import std.utf (f:\usr\pkg\d\dmd\bin\..\import\tangobos\std\utf.d)
import std.c.stdlib (f:\usr\pkg\d\dmd\bin\..\import\tangobos\std\c\stdlib.d)
import std.stdint (f:\usr\pkg\d\dmd\bin\..\import\tangobos\std\stdint.d)
import std.c.stddef (f:\usr\pkg\d\dmd\bin\..\import\tangobos\std\c\stddef.d)
import tango.stdc.errno (f:\usr\pkg\d\dmd\bin\..\import\tango\tango\stdc\errno.d)
import std.c.string (f:\usr\pkg\d\dmd\bin\..\import\tangobos\std\c\string.d)
import std.string (f:\usr\pkg\d\dmd\bin\..\import\tangobos\std\string.d)
import std.uni (f:\usr\pkg\d\dmd\bin\..\import\tangobos\std\uni.d)
import std.array (f:\usr\pkg\d\dmd\bin\..\import\tangobos\std\array.d)
import tango.core.Exception (f:\usr\pkg\d\dmd\bin\..\import\tango\tango\core\Exception.di)
import std.ctype (f:\usr\pkg\d\dmd\bin\..\import\tangobos\std\ctype.d)
import std.gc (f:\usr\pkg\d\dmd\bin\..\import\tangobos\std\gc.d)
import tango.core.Memory (f:\usr\pkg\d\dmd\bin\..\import\tango\tango\core\Memory.di)
import miximport_imp (miximport_imp.d)
semantic2 miximport
semantic3 miximport
code miximport
function this
function main
----
The spec could be fixed, by for instance sticking ImportDeclaration under ClassBodyDeclaration.
A similar issue may pertain to structs, but I haven't tried that.
Relevant discussions of this elsewhere include:
* http://www.dsource.org/projects/dsss/ticket/193
* http://www.dsource.org/forums/viewtopic.php?p=20054#20054
If it is decided that the spec is correct, and this is not legal, then it should be made an error. But I will note that there are libraries in existence that depend on this behavior (namely doost, http://www.dsource.org/projects/doost). There maybe be others, but that's the one where I ran across it.
Comment #1 by clugdbug — 2008-07-14T04:04:14Z
Wow! That's a fantastic feature.
Comment #2 by andrei — 2008-07-14T08:49:08Z
(In reply to comment #1)
> Wow! That's a fantastic feature.
It is pretty interesting, but it would be vastly more so if import would work inside a template and were parameterized with the parameters of the template, or in general if the import could be somehow parameterized. As it is, I'm not seeing many good applications.
For example, say I want to define a module "cloneable" so I can say:
class A { import cloneable; }
class B : A { import cloneable; }
auto x = new A;
auto y = x.clone;
and so on. But in the definition of clone (inside the cloneable module) we'd need the type of the class under construction. Guess that's where typeof(this) would come in handy :o).
Comment #3 by aarti — 2008-07-14T10:16:46Z
(In reply to comment #2)
> It is pretty interesting, but it would be vastly more so if import would work
> inside a template
It works right now, but as Bill noticed is not in specs. See:
http://www.dsource.org/projects/doost/browser/trunk/doost/util/serializer/archive/JsonArchive.d
> and were parameterized with the parameters of the template,
> or in general if the import could be somehow parameterized.
AFAIK according spec template alias parameter can be import also. And maybe mixin("import std.stdio;") will work also... Though I did not test it.
> As it is, I'm not
> seeing many good applications.
With imports in templates it is possible to separate specific implementation from general code. So I would not say that it is not useful :-)
> For example, say I want to define a module "cloneable" so I can say:
>
> class A { import cloneable; }
> class B : A { import cloneable; }
> auto x = new A;
> auto y = x.clone;
Although below already works:
class A { mixin cloneable; }
class B : A { mixin cloneable; }
I used it in serializer, which is parametrized with archive class, and then proper class body is imported into base class.
See:
http://www.dsource.org/projects/doost/browser/trunk/doost/util/serializer/Serializer.d
It works nice, but there is still a lot of rough edges and developing serializer was sometimes really painful. E.g. I can not remove now (in 1.0 branch) spurious parameter to template archive. Program compiles with this argument, but not without it, although template argument (ARCHIVE) is not used anywhere.
> and so on. But in the definition of clone (inside the cloneable module) we'd
> need the type of the class under construction. Guess that's where typeof(this)
> would come in handy :o).
I don't get this part. For me some clarifications would be helpful, but maybe its just me :-)
Comment #4 by wbaxter — 2008-07-14T15:35:02Z
(In reply to comment #2)
> (In reply to comment #1)
> As it is, I'm not seeing many good applications.
It solves the classic problem of how to ensure that you have access to all the symbols that a mixin depends upon.
If in mix.d you have a simple mixin:
import std.stdio;
template() Mix {
void blarf() { writefln("blarf"); }
}
and then you mixin that in a class in another file, that other file also needs to be sure to have writefln accessible. You could make std.stdio a public import of Mix (ick) or selectively make public aliases of all the symbols you use in Mix (easy to forget to update). But both those are foiled if the user decides to use selective import of just Mix.
So what putting the import inside the mixin (and thereby inside the class where it gets mixed in) does is allow you to make sure the dependencies of the mixin always get carried around with the mixin.
I suppose it would also be possible to make aliases to all needed symbols inside the template, but again it's easy to forget one and the list could get quite long. Much easier to just import the modules the mixin needs inside the mixin.
Comment #5 by leandro.lucarella — 2009-11-13T16:38:43Z
See bug 3506 (a feature request for allowing import at any scope).