Thread overview
How to check that import module will succeed?
Jul 26, 2019
Andrey Zherikov
Jul 26, 2019
evilrat
Jul 26, 2019
Anonymouse
Jul 26, 2019
Andrey Zherikov
Jul 26, 2019
Andrey Zherikov
Jul 27, 2019
evilrat
Jul 26, 2019
Paul Backus
Jul 26, 2019
Andrey Zherikov
Jul 26, 2019
Adam D. Ruppe
July 26, 2019
Is there a way to check whether some module, say "foo", is available for import before doing "import foo"?
I want to create a function that imports module if it's available or does something else otherwise. So I think the code should look something like this:

mixin template my_import(alias module_name)
{
    if(module_name is available)
        mixin("import "~module_name~";");
    else
        pragma(msg, module_name~" is not available");
}

mixin my_import!("std.stdio");      // == import std.stdio
mixin my_import!("unknown_module"); // == pragma(msg, "unknown_module is not available")

July 26, 2019
On Friday, 26 July 2019 at 03:42:58 UTC, Andrey Zherikov wrote:
> Is there a way to check whether some module, say "foo", is available for import before doing "import foo"?

I did some really retarded utility like this in the past, worked for me, but I can't say it is that well tested and there might be a better way (after all it just assumes that template instantiation failure can only mean there is no such module), so in short template allowed to fail, and we check if it is failed or not to test if desired module exists. Don't remember if static is really necessary or you can just return directly.

    bool isModuleAvailable(alias modName)() {
        mixin("import " ~ modName ~ ";");
        static if (__traits(compiles, mixin(modName).stringof))
            return true;
        else
            return false;
    }

    // use like this
    static if (__traits(compiles, isModuleAvailable!"mymod" ))
        import mymod;
July 26, 2019
On Friday, 26 July 2019 at 06:24:18 UTC, evilrat wrote:
> On Friday, 26 July 2019 at 03:42:58 UTC, Andrey Zherikov wrote:
>     bool isModuleAvailable(alias modName)() {
>         mixin("import " ~ modName ~ ";");
>         static if (__traits(compiles, mixin(modName).stringof))
>             return true;
>         else
>             return false;
>     }
>
>     // use like this
>     static if (__traits(compiles, isModuleAvailable!"mymod" ))
>         import mymod;

I forgot the exact details but I ran into troubles with this where __traits(compiles, moduleName) would evaluate to false even if the module was available, if there were top-level errors in it.

I use __traits(compiles, __traits(identifier, moduleName)) now instead and it seems to work.
July 26, 2019
On Friday, 26 July 2019 at 03:42:58 UTC, Andrey Zherikov wrote:
> Is there a way to check whether some module, say "foo", is available for import before doing "import foo"?
> I want to create a function that imports module if it's available or does something else otherwise. So I think the code should look something like this:
>
> mixin template my_import(alias module_name)
> {
>     if(module_name is available)
>         mixin("import "~module_name~";");
>     else
>         pragma(msg, module_name~" is not available");
> }
>
> mixin my_import!("std.stdio");      // == import std.stdio
> mixin my_import!("unknown_module"); // == pragma(msg, "unknown_module is not available")

version(HasStdio)
    import std.stdio;
else
    pragma(msg, "std.stdio is not available");

Then configure your build system to pass `-version=HasStdio` to dmd (or the equivalent flag to ldc or gdc) when std.stdio is available.
July 26, 2019
On Friday, 26 July 2019 at 06:24:18 UTC, evilrat wrote:
> On Friday, 26 July 2019 at 03:42:58 UTC, Andrey Zherikov wrote:
>> Is there a way to check whether some module, say "foo", is available for import before doing "import foo"?
>
> I did some really retarded utility like this in the past, worked for me, but I can't say it is that well tested and there might be a better way (after all it just assumes that template instantiation failure can only mean there is no such module), so in short template allowed to fail, and we check if it is failed or not to test if desired module exists. Don't remember if static is really necessary or you can just return directly.
>
>     bool isModuleAvailable(alias modName)() {
>         mixin("import " ~ modName ~ ";");
>         static if (__traits(compiles, mixin(modName).stringof))
>             return true;
>         else
>             return false;
>     }
>
>     // use like this
>     static if (__traits(compiles, isModuleAvailable!"mymod" ))
>         import mymod;

This works, thanks!

But when I try to wrap usage as a single call to something I get slightly different result of import:

// mymod.d
module mymod;
void myfunc() { import std.stdio; writeln("myfunc"); }

// use1.d
static if (__traits(compiles, isModuleAvailable!"mymod" )) import mymod;
pragma(msg,fullyQualifiedName!(myfunc));       // mymod.myfunc
pragma(msg,fullyQualifiedName!(mymod.myfunc)); // mymod.myfunc

// use2.d
mixin template my_import(alias modName)
{
static if (__traits(compiles, isModuleAvailable!modName ))
    mixin("import " ~ modName ~ ";");
}
mixin my_import!"mymod";
pragma(msg,fullyQualifiedName!(myfunc));       // Error: undefined identifier myfunc
pragma(msg,fullyQualifiedName!(mymod.myfunc)); // mymod.myfunc


Even without static if I get the same result:
mixin template my_import(alias modName)
{
    mixin("import " ~ modName ~ ";");
}
mixin my_import!"mymod";
pragma(msg,fullyQualifiedName!(myfunc));       // Error: undefined identifier myfunc
pragma(msg,fullyQualifiedName!(mymod.myfunc)); // mymod.myfunc

If I understood template mixin doc correctly this happens because of "The declarations in a mixin are placed in a nested scope". So is there a way to make two use cases above to work the same way, i.e. "myfunc" to be available without "mymod." prefix?
July 26, 2019
On Friday, 26 July 2019 at 14:14:11 UTC, Anonymouse wrote:
> I use __traits(compiles, __traits(identifier, moduleName)) now instead and it seems to work.

I couldn't find "identifier" docs on https://dlang.org/phobos/std_traits.html. But I tried and it doesn't work - I think because <moduleName> is unknown identifier until "import <moduleName>" is happened.

July 26, 2019
On Friday, 26 July 2019 at 14:19:05 UTC, Paul Backus wrote:
> version(HasStdio)
>     import std.stdio;
> else
>     pragma(msg, "std.stdio is not available");
>
> Then configure your build system to pass `-version=HasStdio` to dmd (or the equivalent flag to ldc or gdc) when std.stdio is available.

I want to achieve similar result without versions.
July 26, 2019
On Friday, 26 July 2019 at 03:42:58 UTC, Andrey Zherikov wrote:
> Is there a way to check whether some module, say "foo", is available for import before doing "import foo"?


  static if (is(typeof((){import that.module.here;}))) {
    // it is available
  }


July 27, 2019
On Friday, 26 July 2019 at 14:56:37 UTC, Andrey Zherikov wrote:
>
> Even without static if I get the same result:
> mixin template my_import(alias modName)
> {
>     mixin("import " ~ modName ~ ";");
> }
> mixin my_import!"mymod";
> pragma(msg,fullyQualifiedName!(myfunc));       // Error: undefined identifier myfunc
> pragma(msg,fullyQualifiedName!(mymod.myfunc)); // mymod.myfunc
>
> If I understood template mixin doc correctly this happens because of "The declarations in a mixin are placed in a nested scope". So is there a way to make two use cases above to work the same way, i.e. "myfunc" to be available without "mymod." prefix?

Exactly. Because of scoping rules mixin templates are nearly useless, there was a lot of frustration/criticism on them, but this is by design - to not turn them in macro hell like in C.
My opinion is that if core team are so picky about explicitness they should also provide a way to explicitly mix into the current scope, but of course I'm just yet another stranger here.

So you can do string mixin instead, however it requires more labor, and usually one has to keep in mind all intricacies of the features used which quickly leads to complexity combinatory explosion.

But whatever... With helper function above you can try this

    @property string my_import(alias mod)()
    {
	return
	"static if (__traits(compiles, isModuleAvailable!\"" ~ mod ~ "\"))" ~
	"{" ~
	" mixin(\"import \",\"" ~ mod ~ "\", \";\"); " ~
	"}";
    }

    // should import into current scope
    mixin(my_import!"std.string");