Jump to page: 1 2
Thread overview
new discovery: import only if available
Jun 19, 2013
Adam D. Ruppe
Jun 19, 2013
Adam D. Ruppe
Jun 19, 2013
Simen Kjaeraas
Jun 19, 2013
Sean Kelly
Jun 19, 2013
Adam D. Ruppe
Jun 19, 2013
Nick Sabalausky
Jun 21, 2013
Adam D. Ruppe
Jun 21, 2013
Simen Kjaeraas
Jun 21, 2013
Rainer Schuetze
Jun 21, 2013
Adam D. Ruppe
June 19, 2013
I watched the shared libraries in D video earlier today and one of the things mentioned was using a library only if it is available, and it rekindled something I wanted to do a while ago and couldn't: expand a module if and only if some other module is available.

Well, I could do it, but it meant using -versions. I'd prefer it if it worked with just listing the module.

But I think I have a solution now:

template moduleIsAvailable(string name) {
	enum moduleIsAvailable =
		mixin("__traits(compiles, { import " ~ name ~ "; } )")
		? true : false;
}

        pragma(msg, moduleIsAvailable!"test");
        pragma(msg, moduleIsAvailable!"not.existing");

It returned true and false, so cool. If a module is available though, this test actually imports it and if you don't add its object file, you'll get a linker error:

$ dmd test11
true
false
test11.o:(.data+0x50): undefined reference to `_D4test12__ModuleInfoZ'


But that might be ok, since if it is available, you'll probably be using it anyway - if not, why would you test? Though it would be cool if there was some kind of technique we could use such that it only pulls if the module is actually used elsewhere, like a low priority linker symbol or something. But I don't know about that.


Anyway, with this, you can wrap the usage of a module inside a static if(moduleIsAvailable) {} and offer some magical expansion of interoperability (though, granted, this kind of thing might be best put into a third module anyway), or a graceful degradation if you want a file to combine with a library and be standalone at the same time.


The -version method might be better anyway though, since it is more explicit.... so I'm on the fence as to if I should actually use this. What do you all think? Bad idea or worth doing to have one file be both standalone and interconnected at the same time?
June 19, 2013
whoa, I was just about go to bed, but turned the computer on because I just thought of one case where I think I want to do this: config files.

For my work apps, if I need config I always do them as a module:

config_a.d
===
module application.config;

enum featureA = true;
string appName = "Acme Software";
===


The selective module magic could be used to offer a default configuration, with the import overriding it if available:

static if(importIsAvailable!"app.config") {
   import app.config;
} else {
   enum featureA = false;
   string appName= "My App";
}

. That's potentially way cool.
June 19, 2013
On Wed, 19 Jun 2013 04:37:10 +0200, Adam D. Ruppe <destructionator@gmail.com> wrote:

> If a module is available though, this test actually imports it and if you don't add its object file, you'll get a linker error:
>
> $ dmd test11
> true
> false
> test11.o:(.data+0x50): undefined reference to `_D4test12__ModuleInfoZ'

As you say this might be acceptable, but I would still call it a bug - it's
complaining about symbols that have no business being in the obj file.

-- 
Simen
June 19, 2013
On Jun 18, 2013, at 7:37 PM, Adam D. Ruppe <destructionator@gmail.com> wrote:
> 
> It returned true and false, so cool. If a module is available though, this test actually imports it and if you don't add its object file, you'll get a linker error:
> 
> $ dmd test11
> true
> false
> test11.o:(.data+0x50): undefined reference to `_D4test12__ModuleInfoZ'
> 
> 
> But that might be ok, since if it is available, you'll probably be using it anyway - if not, why would you test? Though it would be cool if there was some kind of technique we could use such that it only pulls if the module is actually used elsewhere, like a low priority linker symbol or something. But I don't know about that.

rdmd?
June 19, 2013
On Wednesday, 19 June 2013 at 19:20:15 UTC, Sean Kelly wrote:
> rdmd?

That would pull it in here. What I mean is if:

module a: "weakly" imports module c
module b: imports module c


Module c is available, but:

dmd a.d c.d

explicitly uses module c, so it is pulled.

dmd a.d

only uses module a, because module c isn't used elsewhere and isn't explicitly pulled in.


dmd a.d b.d

does use module c, because it is required anyway by module b.
June 19, 2013
On Wed, 19 Jun 2013 04:37:10 +0200
"Adam D. Ruppe" <destructionator@gmail.com> wrote:
> 
> template moduleIsAvailable(string name) {
> 	enum moduleIsAvailable =
> 		mixin("__traits(compiles, { import " ~ name ~ "; } )")
> 		? true : false;
> }
> 
>          pragma(msg, moduleIsAvailable!"test");
>          pragma(msg, moduleIsAvailable!"not.existing");
> 

I do that "__traits(compiles, {import blah;})" trick too, although I've never generalized it. Nice util.

I find the trick useful for generating a clean error message if something is missing, like a configuration file written in D, or a -version that introduces a dependency on a certain external module but doesn't find it.

June 19, 2013
On 6/19/13 3:42 PM, Adam D. Ruppe wrote:
> On Wednesday, 19 June 2013 at 19:20:15 UTC, Sean Kelly wrote:
>> rdmd?
>
> That would pull it in here. What I mean is if:
>
> module a: "weakly" imports module c
> module b: imports module c
>
>
> Module c is available, but:
>
> dmd a.d c.d
>
> explicitly uses module c, so it is pulled.
>
> dmd a.d
>
> only uses module a, because module c isn't used elsewhere and isn't
> explicitly pulled in.
>
>
> dmd a.d b.d
>
> does use module c, because it is required anyway by module b.

Yah, you'd need something like rdmd **/*.d.

Andrei
June 21, 2013
OMG guys this finishes the druntime extension problem!


Try it yourself, open up dmd2/src/druntime/import/object.di and find template RTInfo.

Change it to this:

template RTInfo(T)
{
    static if(__traits(compiles, { import druntime.extensions; auto a =  druntime.extensions.    RTInfo!T; })) {
        import druntime.extensions;
         enum RTInfo = druntime.extensions.RTInfo!T;
    } else
        enum RTInfo = cast(void*)0x12345678;
}



Make a test program with just "struct Test {} "

And a helper file with contents:

===
module druntime.extensions;

template RTInfo(T) {
        static if(T.stringof == "Test") {
                pragma(msg, "Here!");
        }

        enum RTInfo = null;
}
==



Compile without extensions:

$ dmd test23 -main
$


No messages, no errors, just as it should be.


Now add our helper file to the command line....


$ dmd test23 -main dext.d
Here!
$


It triggered! Boom, we have the potential for *project-wide* modifications to RTInfo without modifying druntime. Combine this with the other techniques I've talked about for rtinfo and we have it all.

You wouldn't necessarily have to add it specifically to the command line btw, you could put it in a file called druntime/extensions.d in your import directory as well, especially since it is a template.
June 21, 2013
On Fri, 21 Jun 2013 14:41:29 +0200, Adam D. Ruppe <destructionator@gmail.com> wrote:

> OMG guys this finishes the druntime extension problem!

That is awesome. Make a pull request.

-- 
Simen
June 21, 2013

On 21.06.2013 14:41, Adam D. Ruppe wrote:
> OMG guys this finishes the druntime extension problem!
>
>
> Try it yourself, open up dmd2/src/druntime/import/object.di and find
> template RTInfo.
>
> Change it to this:
>
> template RTInfo(T)
> {
>      static if(__traits(compiles, { import druntime.extensions; auto a
> =  druntime.extensions.    RTInfo!T; })) {
>          import druntime.extensions;
>           enum RTInfo = druntime.extensions.RTInfo!T;
>      } else
>          enum RTInfo = cast(void*)0x12345678;
> }

I guess you should move the "static if" outside of the template to avoid having it evaluated for every type. This can be pretty expensive as it includes a file search every time if it fails.

>
> It triggered! Boom, we have the potential for *project-wide*
> modifications to RTInfo without modifying druntime. Combine this with
> the other techniques I've talked about for rtinfo and we have it all.
>
> You wouldn't necessarily have to add it specifically to the command line
> btw, you could put it in a file called druntime/extensions.d in your
> import directory as well, especially since it is a template.

I was considering something similar, maybe this could even be extended to allow combining multiple extensions to work side-by-side.

I'm unsure though if this is too brittle with respect to linking something together that might be compiled with or without these extensions.
« First   ‹ Prev
1 2