another cool RTInfo trick - i want in runtime

Adam D. Ruppe destructionator at gmail.com
Thu Jan 16 07:57:04 PST 2014


Check this out. Modify your druntime slightly. In object.di, find 
template RTInfo(T) and add this bit:

     import core.config;
     alias checkResult = TypeCheck!T;

Then, pop open import/core/config.d and put these contents in it:

module core.config;
template TypeCheck(T) {
     enum TypeCheck = true;
}


Compile a program, any program. Should be no difference in 
anything - no errors, no changes to the binary, no compile 
slowdown - from before the modifications.


Now, create a file named anything you want with these contents:

module core.config;
template TypeCheck(T) {
   static if(T.stringof == "Cool")
     static assert(0, "No type named 'Cool' is allowed!");
   enum TypeCheck = true;
}


Compile your program, should still work. Then add "struct Cool{}" 
to it anywhere... and you get a compile error.



Brothers and sisters, I've talked to you before about doing 
custom RTInfo using __traits(compiles) tricks to look for the 
config module, but my previous ways - while they worked - sucked 
because the compiler would look for the module over and over 
again, slowing things down a bit.

This new method achieves success on all counts. By offering a 
file with druntime to be the module up front, the compiler does 
no special searching, it finds it. It is a trivial file, so 
impact on compile speed is negligible.

But then, if you offer your own file with the same module name on 
the command line, dmd looks THERE first, finds your special code, 
and knows to skip searching the import path! Even true for 
object.d, since this is all in templates with local imports; the 
template still needs to be instantiated.

Since this object.d doesn't actually store anything* in the 
RTInfo itself, there's no worry of binary incompatibilities 
resulting from separate compiliation with different rtinfo 
modules. It simply provides a hook into the types for checking.

Using this, we can automatically check all kinds of per-project 
requirements. Don't want virtual functions in your class unless 
they are reviewed? Make your TypeCheck loop over them and look 
for a UDA, issuing a static assert if not there. Don't want 
references to un-owned mutable data? Ditto. Have a naming 
convention to check? Can do that too.


I see lots of upsides, and the downsides from my last experiment 
with this I believe have been eliminated. Am I missing something? 
I wanna do a druntime pull request!


* User data extensions could potentially be allowed if RTInfo 
stored a pointer to an interface, which may be null. Other 
modules may implement the interface differently, but as long as 
they implement it (or set it to null), it should still have 
consistent binary compatibility.

You might make object.d's RTInfo create a static struct with 
information the GC needs first, then a pointer to the user 
defined data. The RTInfo template ultimately resolves to the 
pointer to that struct. The data itself is consistent - still 
defined in only one place, druntime itself, and the GC info is 
available right there, no added indirection, and we have the hook 
for user additions too, all under a consistent interface.

You can also add runtime info about a type using static 
constructors:
===
module core.config;

string[] types;

template TypeCheck(T) {
     enum TypeCheck = true;

     shared static this() {
         types ~= T.mangleof;
     }
}
===
module test500.d
struct Cool {}

void main() {
	import core.config, std.stdio;
	writeln(types);
}
===
dmd test500.d rtinfo.d

$ ./test500
["S7test5004Cool", 
"S3std5array17__T8AppenderTAyaZ8Appender4Data", 
"S3std5array17__T8AppenderTAyaZ8Appender"]


Run time info available about all the types used in that program!


Soooo yeah, this is pretty much a pure win all around to my eyes. 
Am I blind to the suck?


More information about the Digitalmars-d mailing list