Thread overview
Loop through all modules and module members?
Dec 31, 2010
%u
Jan 01, 2011
bearophile
Jan 01, 2011
Philippe Sigaud
Jan 01, 2011
Andrej Mitrovic
Jan 01, 2011
Andrej Mitrovic
Jan 02, 2011
Philippe Sigaud
Jan 02, 2011
Andrej Mitrovic
December 31, 2010
Hi,

I would like to perform compile-time reflection on a module (such as enumerating all the classes inside the module) and/or on all modules in the code -- are either of these possible? And if so, how?

Thank you!
January 01, 2011
%u:

> I would like to perform compile-time reflection on a module (such as enumerating all the classes inside the module) and/or on all modules in the code -- are either of these possible? And if so, how?

You may add your enhancement requests here, explaining why you need them: http://d.puremagic.com/issues/show_bug.cgi?id=4476

At the moment the static reflection is not able to do everything. Listing all modules in the code looks like work for rmdm. Listing all classes in a module seems work for __traits/meta, plus a compile-time Filter.

Bye,
bearophile
January 01, 2011
On Sat, Jan 1, 2011 at 11:14, bearophile <bearophileHUGS@lycos.com> wrote:
> %u:
>
>> I would like to perform compile-time reflection on a module (such as enumerating all the classes inside the module) and/or on all modules in the code -- are either of these possible? And if so, how?
>
> You may add your enhancement requests here, explaining why you need them: http://d.puremagic.com/issues/show_bug.cgi?id=4476
>
> At the moment the static reflection is not able to do everything. Listing all modules in the code looks like work for rmdm. Listing all classes in a module seems work for __traits/meta, plus a compile-time Filter.

Yes, it's doable :

template StaticFilter(alias Pred, T...)
{
    static if (T.length == 0)
        alias TypeTuple!() StaticFilter;
    else static if (Pred!(T[0]))
        alias TypeTuple!(T[0], StaticFilter!(Pred, T[1 .. $])) StaticFilter;
    else
        alias StaticFilter!(Pred, T[1 .. $]) StaticFilter;
}

template isClass(string name)
{
mixin("
      static if (is(" ~ name ~ " == class))
          enum bool isClass = true;
      else
        enum bool isClass = false;");
}

template extractClasses(string moduleName, members...)
{
    alias StaticFilter!(isClass,members) extractClasses;
}

template classMembers(string moduleName)
{
    mixin("alias extractClasses!(moduleName, __traits(allMembers, " ~
moduleName ~ ")) classMembers;");
}


if in module dir.mod1.d you have

class A {}
class B : A {}
struct S {}
class C {}
int foo() { return 0;}

then

classMembers!("dir.mod1") will become the tuple ("A", "B", "C") during
compilation.

It's buggy, though: the module needs to be in a directory. You cannot
do classMembers!("mod1"). Too bad.
Note that class templates are *not* classes. So most of std.* modules
will return an empty tuple, because they're full of templates.
Another detail I didn't have the time to correct: the names should be
tested fully qualified, to avoid any name clash with locally-defined
classes.

As for listing all modules imported by a module, I have something, but it's not very elegant: it scans the text, looking for import declarations. It works, but at runtime. I'm not sure it's doable at compile-time right now: you need to have access to the module code, as text. Do imports work in CT-evaluable functions?

Philippe
January 01, 2011
On 1/1/11, Philippe Sigaud <philippe.sigaud@gmail.com> wrote:
> I'm not sure it's doable at
> compile-time right now: you need to have access to the module code, as
> text. Do imports work in CT-evaluable functions?
>
> Philippe
>

You're gonna love this:

module mymodule;

void main()
{
    pragma(msg, import(.stringof[7..$] ~ ".d"));
}

Of course, you need to -J switch with the path of your module.
January 01, 2011
*the* J switch.

On 1/1/11, Andrej Mitrovic <andrej.mitrovich@gmail.com> wrote:
> On 1/1/11, Philippe Sigaud <philippe.sigaud@gmail.com> wrote:
>> I'm not sure it's doable at
>> compile-time right now: you need to have access to the module code, as
>> text. Do imports work in CT-evaluable functions?
>>
>> Philippe
>>
>
> You're gonna love this:
>
> module mymodule;
>
> void main()
> {
>     pragma(msg, import(.stringof[7..$] ~ ".d"));
> }
>
> Of course, you need to -J switch with the path of your module.
>
January 02, 2011
On Sat, Jan 1, 2011 at 18:56, Andrej Mitrovic <andrej.mitrovich@gmail.com> wrote:
> On 1/1/11, Philippe Sigaud <philippe.sigaud@gmail.com> wrote:
>> I'm not sure it's doable at
>> compile-time right now: you need to have access to the module code, as
>> text. Do imports work in CT-evaluable functions?
>>
>> Philippe
>>
>
> You're gonna love this:
>
> module mymodule;
>
> void main()
> {
>    pragma(msg, import(.stringof[7..$] ~ ".d"));
> }

I saw your .stringof trick a few days ago and it made my day :-)
But I didn't know you could text-import at compile-time (with access
for the programmer, I mean. Obviously the compiler can import at CT).
Cool!

OK, then it's doable to get a compile-time list of imported modules from a module name. Too bad modules are not first class in D: would they have type, we could return a list of them [std.algorithm, std.concurrency, ...]


> Of course, you need to -J switch with the path of your module.

I'm not much versed in DMD switches. I'll try and see.

Philippe
January 02, 2011
On 1/2/11, Philippe Sigaud <philippe.sigaud@gmail.com> wrote:
>> Of course, you need to -J switch with the path of your module.
>
> I'm not much versed in DMD switches. I'll try and see.
>
> Philippe
>

Well it's a simple switch, really. If the module is in "C:\dev\project\", use: dmd -JC:\dev\project\

On *nix it's the same, I believe.

http://www.digitalmars.com/d/2.0/dmd-windows.html#switches http://www.digitalmars.com/d/2.0/dmd-linux.html#switches