digitalmars.D - new discovery: import only if available
- Adam D. Ruppe (39/39) Jun 18 2013 I watched the shared libraries in D video earlier today and one
- Adam D. Ruppe (19/19) Jun 18 2013 whoa, I was just about go to bed, but turned the computer on
- Simen Kjaeraas (6/12) Jun 18 2013 As you say this might be acceptable, but I would still call it a bug - i...
- Sean Kelly (9/19) Jun 19 2013 this test actually imports it and if you don't add its object file, =
- Adam D. Ruppe (12/13) Jun 19 2013 That would pull it in here. What I mean is if:
- Andrei Alexandrescu (3/16) Jun 19 2013 Yah, you'd need something like rdmd **/*.d.
- Nick Sabalausky (8/18) Jun 19 2013 I do that "__traits(compiles, {import blah;})" trick too,
- Adam D. Ruppe (40/40) Jun 21 2013 OMG guys this finishes the druntime extension problem!
- Simen Kjaeraas (5/6) Jun 21 2013 That is awesome. Make a pull request.
- Rainer Schuetze (8/27) Jun 21 2013 I guess you should move the "static if" outside of the template to avoid...
- Adam D. Ruppe (12/18) Jun 21 2013 Probably.... also the __traits(compiles) in there is a mistake,
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?
Jun 18 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.
Jun 18 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
Jun 18 2013
On Jun 18, 2013, at 7:37 PM, Adam D. Ruppe <destructionator gmail.com> = wrote:=20 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:=20 $ dmd test11 true false test11.o:(.data+0x50): undefined reference to `_D4test12__ModuleInfoZ' =20 =20 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?=
Jun 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.
Jun 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:Yah, you'd need something like rdmd **/*.d. Andreirdmd?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.
Jun 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.
Jun 19 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.
Jun 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
Jun 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.
Jun 21 2013
On Friday, 21 June 2013 at 18:47:24 UTC, Rainer Schuetze wrote: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.Probably.... also the __traits(compiles) in there is a mistake, because that breaks any static assert(0)'s in the extension code, so want to take that out too. The other thing I'm thinking is maybe it should be a mixin template or something, because if it is supposed to be an extension, we don't want it completely replacing what druntime has. It should just add to it. This might need a cast and/or some indirection to keep straight through typeinfo.rtInfo() though.I'm unsure though if this is too brittle with respect to linking something together that might be compiled with or without these extensions.The linker would probably complain about the symbol changing sizes if you did it wrong, There'd be some brittleness but maybe that's ok because not everyone would be tweaking this anyway.
Jun 21 2013