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