www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - core.reflect vs. __traits

reply Stefan Koch <uplink.coder googlemail.com> writes:
Good Day D Community,

I just did a little test run of using `core.reflect` on the `enum 
TOK` within DMD.
(Which was successful yay. ;))

Then I compared it against the `__traits` version.

```
import dmd.tokens;
version(UseCoreReflect)
{
   import core.reflect.reflect;
   static immutable e = cast(immutable EnumDeclaration) 
nodeFromName("TOK");

   pragma(msg,
     () {
       import std.conv;
       string result;

       result ~= "enum " ~ e.name ~ " {\n";

       foreach(m;e.members)
       {
           IntegerLiteral l = cast(IntegerLiteral) m.value;
           result ~= "  " ~ m.name ~ " = " ~ to!string(l.value) ~ 
",\n";
       }

       result ~= "}";
       return result;
     } ()
   );

}

version(UseTraits)
{
   enum members = __traits(allMembers, TOK);

   pragma(msg,
     () {
       import std.conv;
       string result;

       result ~= "enum " ~ TOK.stringof ~ "{\n";

       static foreach(m;members)
       {
           result ~= "  " ~ m ~ " = " ~ 
to!string(cast(int)mixin("TOK." ~ m)) ~ ",\n";
       }

       result ~= "}";
       return result;
     } ()
   );
}
```

In terms of code I do prefer the `core.traits` version because 
that one does not use a mixin and doesn't force you to do a 
`static foreach` also it can trivially be factored into a runtime 
function which doesn't stress CTFE out. Whereas the `__traits` 
version cannot trivially be factored to do most of the work at 
runtime.
I guess you could build a `string[]` with member names and index 
that runtime but it's not as trivial as just calling the function 
at runtime with an `EnumDeclaration` object generated at compile 
time.

Please let me know what you think.

P.S. In terms of performance the `core.reflect` version is faster 
by 2%  on average which doesn't matter in the slightest using 
such tiny test-cases.
Jul 03 2021
next sibling parent reply zjh <fqbqrr 163.com> writes:
On Saturday, 3 July 2021 at 11:59:03 UTC, Stefan Koch wrote:
 Good Day D Community,
When can we used `core.reflect`?
Jul 03 2021
parent Stefan Koch <uplink.coder googlemail.com> writes:
On Saturday, 3 July 2021 at 12:44:00 UTC, zjh wrote:
 On Saturday, 3 July 2021 at 11:59:03 UTC, Stefan Koch wrote:
 Good Day D Community,
When can we used `core.reflect`?
I am not sure ;) At this point it's a prototype which I have been developing for less than 2 weeks. As soon it works consistently performant on large code-bases. The last thing D needs is another toy feature that breaks down under stress and pressure.
Jul 03 2021
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 7/3/21 7:59 AM, Stefan Koch wrote:
            result ~= "  " ~ m ~ " = " ~
to!string(cast(int)mixin("TOK." 
 ~ m)) ~ ",\n";
"because [the `__traits` version uses] a mixin" What about: ```d result ~= " " ~ m ~ " = " ~ to!string(int(__traits(getMember, TOK, m))) ~ ",\n"; ``` -Steve
Jul 03 2021
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Saturday, 3 July 2021 at 13:09:26 UTC, Steven Schveighoffer 
wrote:
 On 7/3/21 7:59 AM, Stefan Koch wrote:
            result ~= "  " ~ m ~ " = " ~ 
 to!string(cast(int)mixin("TOK." ~ m)) ~ ",\n";
"because [the `__traits` version uses] a mixin" What about: ```d result ~= " " ~ m ~ " = " ~ to!string(int(__traits(getMember, TOK, m))) ~ ",\n"; ``` -Steve
That needs TOK as a template type parameter as well. and therefore forces you to extract the strings at compile time into an auxiliary data-structure. (most likely `string[]`)
Jul 03 2021
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 7/3/21 9:15 AM, Stefan Koch wrote:
 On Saturday, 3 July 2021 at 13:09:26 UTC, Steven Schveighoffer wrote:
 On 7/3/21 7:59 AM, Stefan Koch wrote:
            result ~= "  " ~ m ~ " = " ~ 
 to!string(cast(int)mixin("TOK." ~ m)) ~ ",\n";
"because [the `__traits` version uses] a mixin" What about: ```d result ~= " " ~ m ~ " = " ~ to!string(int(__traits(getMember, TOK, m))) ~ ",\n"; ```
That needs TOK as a template type parameter as well. and therefore forces you to extract the strings at compile time into an auxiliary data-structure. (most likely `string[]`)
My point is, if `mixin("TOK." ~ m)` works, then `__traits(getMember, TOK, m)` should also, and therefore no mixin required. -Steve
Jul 03 2021
parent Stefan Koch <uplink.coder googlemail.com> writes:
On Saturday, 3 July 2021 at 15:09:38 UTC, Steven Schveighoffer 
wrote:
 On 7/3/21 9:15 AM, Stefan Koch wrote:
 On Saturday, 3 July 2021 at 13:09:26 UTC, Steven Schveighoffer 
 wrote:
 On 7/3/21 7:59 AM, Stefan Koch wrote:
            result ~= "  " ~ m ~ " = " ~ 
 to!string(cast(int)mixin("TOK." ~ m)) ~ ",\n";
"because [the `__traits` version uses] a mixin" What about: ```d result ~= " " ~ m ~ " = " ~ to!string(int(__traits(getMember, TOK, m))) ~ ",\n"; ```
That needs TOK as a template type parameter as well. and therefore forces you to extract the strings at compile time into an auxiliary data-structure. (most likely `string[]`)
My point is, if `mixin("TOK." ~ m)` works, then `__traits(getMember, TOK, m)` should also, and therefore no mixin required. -Steve
Fair point. And getMember does look somewhat nicer than the string mixin as well ;)
Jul 03 2021
prev sibling next sibling parent Bruce Carneal <bcarneal gmail.com> writes:
On Saturday, 3 July 2021 at 11:59:03 UTC, Stefan Koch wrote:
 [big snip]

 Please let me know what you think.
Nice! The eminently readable structs/API displace the current all-in-the-programmers-head meta programming "type" systems (various collections of strings, conventions, yet-more-layering, alls-you-gotta-do-is-recur hacks, if-you-were-a-*real*-programmer-you'd-find-this-trivial hacks, ...). With changes like these meta programming starts to look less special, less heroic. That's a good look. Good luck in your further explorations.
Jul 03 2021
prev sibling parent reply Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Saturday, 3 July 2021 at 11:59:03 UTC, Stefan Koch wrote:
 Good Day D Community,
   ...
 Please let me know what you think.
Hi, any thoughts, on integrating core.reflect with typeinfo classes? Seems like, right place for reflection information to be stored. Also any plans on providing a good interface for invoking functions and class members? Would be nice to have two sets of functionality, one for compile time, and one at run time. Best regards, Alexandru.
Jul 03 2021
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Saturday, 3 July 2021 at 15:46:07 UTC, Alexandru Ermicioi 
wrote:
 On Saturday, 3 July 2021 at 11:59:03 UTC, Stefan Koch wrote:
 Good Day D Community,
   ...
 Please let me know what you think.
Hi, any thoughts, on integrating core.reflect with typeinfo classes? Seems like, right place for reflection information to be stored. Also any plans on providing a good interface for invoking functions and class members? Would be nice to have two sets of functionality, one for compile time, and one at run time. Best regards, Alexandru.
typeinfo is a failed experiment in my opinion which has never been useful and this is why I am working on `core.reflect`. The functionality for runtime and for compile time (as far as working with reflection classes in concerned) should be the same. Of course, the to be unveiled `core.codegen` cannot work at runtime.
Jul 03 2021
parent Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Saturday, 3 July 2021 at 16:08:59 UTC, Stefan Koch wrote:
 On Saturday, 3 July 2021 at 15:46:07 UTC, Alexandru Ermicioi 
 wrote:
 On Saturday, 3 July 2021 at 11:59:03 UTC, Stefan Koch wrote:
 Good Day D Community,
   ...
 Please let me know what you think.
Hi, any thoughts, on integrating core.reflect with typeinfo classes? Seems like, right place for reflection information to be stored. Also any plans on providing a good interface for invoking functions and class members? Would be nice to have two sets of functionality, one for compile time, and one at run time. Best regards, Alexandru.
typeinfo is a failed experiment in my opinion which has never been useful and this is why I am working on `core.reflect`.
Why do you think it is a failed experiment? From the looks of it reflection info you're designing has perfect place: TypeInfo. Of course, current type info architecture might not be satisfactory, but with some improvements it can accommodate core.reflect functionality. It's true, type info seems half finished thing, but for features it already provides it is quite useful, which mainly is type identification at runtime. For example my pet project aedi which is a dependency injection container, boxes all managed components and erases their type when stored in a container. If an user wants a component out of container, it will check whether the desired component matches the type client expects by doing a typeinfo equality check, and if not throw an exception.
 The functionality for runtime and for compile time (as far as 
 working with reflection classes in concerned) should be the 
 same.
So say given a name of a method as string and an instance of a class that has that method at runtime (not ctfe) will I be able to call that said method on the instance?
Jul 04 2021