Jump to page: 1 2 3
Thread overview
another cool RTInfo trick - i want in runtime
Jan 16, 2014
Adam D. Ruppe
Jan 16, 2014
Vladimir Panteleev
Jan 16, 2014
Adam D. Ruppe
Jan 16, 2014
Vladimir Panteleev
Jan 16, 2014
Adam D. Ruppe
Jan 16, 2014
Vladimir Panteleev
Jan 16, 2014
Vladimir Panteleev
Jan 16, 2014
Dicebot
Jan 16, 2014
Vladimir Panteleev
Jan 16, 2014
Adam D. Ruppe
Jan 16, 2014
Namespace
Jan 16, 2014
Adam D. Ruppe
Jan 16, 2014
Namespace
Jan 16, 2014
Namespace
Jan 16, 2014
Adam D. Ruppe
Jan 17, 2014
Meta
Jan 17, 2014
Adam D. Ruppe
Jan 17, 2014
Marco Leise
Jan 17, 2014
Adam D. Ruppe
Jan 17, 2014
Michel Fortin
Jan 16, 2014
Jacob Carlborg
Jan 17, 2014
Adam D. Ruppe
Jan 17, 2014
Jacob Carlborg
Jan 16, 2014
Marco Leise
Jan 17, 2014
Adam D. Ruppe
Jan 17, 2014
Marco Leise
Jan 16, 2014
Tove
January 16, 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?
January 16, 2014
On Thursday, 16 January 2014 at 15:57:05 UTC, Adam D. Ruppe wrote:
> Now, create a file named anything you want with these contents:

I guess this won't work with rdmd, then?
January 16, 2014
On Thursday, 16 January 2014 at 16:09:52 UTC, Vladimir Panteleev wrote:
> I guess this won't work with rdmd, then?

That's due to a deficiency in rdmd: tt doesn't let you forward all the available module options to dmd, even though it would make sense to do it, for this kind of replaceable config module thing and also for replacing say one phobos file at a time for doing dev work on that . rdmd should be fixed to allow you to pass more than one explicit module (maybe just add an option like --additional-dmd-option=file.d).
January 16, 2014
On Thursday, 16 January 2014 at 16:21:25 UTC, Adam D. Ruppe wrote:
> On Thursday, 16 January 2014 at 16:09:52 UTC, Vladimir Panteleev wrote:
>> I guess this won't work with rdmd, then?
>
> That's due to a deficiency in rdmd: tt doesn't let you forward all the available module options to dmd, even though it would make sense to do it, for this kind of replaceable config module thing and also for replacing say one phobos file at a time for doing dev work on that . rdmd should be fixed to allow you to pass more than one explicit module (maybe just add an option like --additional-dmd-option=file.d).

That sounds overcomplicated.

Why not move the standard search paths to after the users' ones? So that users can override Phobos and Druntime modules simply by creating them within their search path.
January 16, 2014
On Thursday, 16 January 2014 at 16:26:49 UTC, Vladimir Panteleev wrote:
> Why not move the standard search paths to after the users' ones?

That might work too. Either way though, the compiler and language let you list additional modules and it all just works if you do, so rdmd should too... however it does.

I don't use rdmd myself so the specific solution should probably be guided by people who do.
January 16, 2014
On Thursday, 16 January 2014 at 16:37:16 UTC, Adam D. Ruppe wrote:
> I don't use rdmd myself so the specific solution should probably be guided by people who do.

Well, the beauty of rdmd is that you don't need to mess with options in the general case. My setup is that generally I press "Enter" on a .d file and it is built into an .exe (if there is an entry point in any imported modules) - no other action required. If I had to modify the command line for every invocation, that would not work for my case, so I'd have to write a rdmd wrapper to look for additional command-line options in a configuration file in the current directory, or implement something like that in rdmd itself.

If these requirements can be specified in the source code itself, that would be much better. In our case it would simply be the presence of a file in the project search path. An existing example of this is pragma(lib) - instead of telling the user to specify which libraries to add to the linker command line, or providing a makefile (with all its problems), a pragma(lib) can be used to pull in those libraries automatically.
January 16, 2014
On Thursday, 16 January 2014 at 16:26:49 UTC, Vladimir Panteleev wrote:
> Why not move the standard search paths to after the users' ones? So that users can override Phobos and Druntime modules simply by creating them within their search path.

Never mind, this is already the case! It depends on how you write your own sc.ini (I had mine with Phobos/Druntime in front).
January 16, 2014
On Thursday, 16 January 2014 at 17:10:42 UTC, Vladimir Panteleev wrote:
> On Thursday, 16 January 2014 at 16:26:49 UTC, Vladimir Panteleev wrote:
>> Why not move the standard search paths to after the users' ones? So that users can override Phobos and Druntime modules simply by creating them within their search path.
>
> Never mind, this is already the case! It depends on how you write your own sc.ini (I had mine with Phobos/Druntime in front).

Probably we should pick one way or another as standard for packaging so that projects can rely on it.
January 16, 2014
On Thursday, 16 January 2014 at 15:57:05 UTC, Adam D. Ruppe wrote:
> Check this out. Modify your druntime slightly. In object.di, find template RTInfo(T) and add this bit:

Suggestions:

1. I guess TypeCheck is a temporary name? I would suggest e.g. CustomRTInfo.

2. How about using a template mixin instead of a template? Then you can drop the dummy bool. I know that if you use a mixin, you can't refer to stuff that's in the scope where it's declared, but I think that's OK - because you probably don't want an object file for config.d anyway, since:

3. rdmd will not add config.d to the compiler's command line, since it lies in an excluded package "core" (so it's assumed it'll be in phobos.lib). But that's OK, since there will be no symbols in config.d to link against anyway!

It all fits together quite nicely. You can access stuff in your main program by importing its modules within the template mixin.
January 16, 2014
On Thursday, 16 January 2014 at 15:57:05 UTC, Adam D. Ruppe wrote:
> 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?

I guess that could work pretty well for a C++ friend emulation with UDA's! Were not you the one who wanted to show me an example for that with using RTInfo?

Offer your way the possibility to check automatically for null references? With an UDA e.g. @safe_ref or @not_null
« First   ‹ Prev
1 2 3