www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - core.reflect vs c++ reflection

reply Stefan Koch <uplink.coder googlemail.com> writes:
Good day,

It's hard to find good examples of the c++ reflection ts so I've 
copied one I've found in an earlier proposal
I am just putting the proposed c++ syntax here, next to how my 
core.reflect library would handle this case.


```C
#include <meta>
template<Enum T>
std::string to_string(T value) { // Could also be marked constexpr
     for constexpr (auto e : std::meta::members_of(reflexpr(T)) {
         if (exprid(e) == value) {
             return std::meta::name_of(e);
         }
     }
     return "<unnamed>";
}
```

```D
import core.reflect.reflect;
string toString(E)(E enumValue)
{
     static immutable ed = cast(EnumDeclaration)nodeFromName(E);
     foreach(m; ed.members)
     {
         if ((cast(IntegerLiteral)m.value).value == enumValue)
         {
             return m.name;
         }
     }
     return "unnamed";
}
```

Please let know what you think.
Sep 26 2021
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Sunday, 26 September 2021 at 19:03:24 UTC, Stefan Koch wrote:
 Good day,
 Please let know what you think.
Ugh typo.
static immutable ed = cast(EnumDeclaration)nodeFromName(E);
is supposed to be: `static immutable ed = cast(EnumDeclaration)nodeFromName("E");`
Sep 26 2021
parent reply bauss <jj_1337 live.dk> writes:
On Sunday, 26 September 2021 at 19:09:31 UTC, Stefan Koch wrote:
 On Sunday, 26 September 2021 at 19:03:24 UTC, Stefan Koch wrote:
 Good day,
 Please let know what you think.
Ugh typo.
static immutable ed = cast(EnumDeclaration)nodeFromName(E);
is supposed to be: `static immutable ed = cast(EnumDeclaration)nodeFromName("E");`
What about E.stringof? Instead of hardcoding names :) Not sure if stringof will return E in all cases, so obviously only if it works.
Sep 26 2021
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Monday, 27 September 2021 at 06:25:07 UTC, bauss wrote:
 On Sunday, 26 September 2021 at 19:09:31 UTC, Stefan Koch wrote:
 On Sunday, 26 September 2021 at 19:03:24 UTC, Stefan Koch 
 wrote:
 Good day,
 Please let know what you think.
Ugh typo.
static immutable ed = cast(EnumDeclaration)nodeFromName(E);
is supposed to be: `static immutable ed = cast(EnumDeclaration)nodeFromName("E");`
What about E.stringof? Instead of hardcoding names :) Not sure if stringof will return E in all cases, so obviously only if it works.
E stringof would return the name of the type; In simple cases and garbage in others. Whereas the name E always refers to the type used in the toString template. Also "E" is less typing than E.stringof
Sep 27 2021
parent reply bauss <jj_1337 live.dk> writes:
On Monday, 27 September 2021 at 07:28:46 UTC, Stefan Koch wrote:
 On Monday, 27 September 2021 at 06:25:07 UTC, bauss wrote:
 On Sunday, 26 September 2021 at 19:09:31 UTC, Stefan Koch 
 wrote:
 On Sunday, 26 September 2021 at 19:03:24 UTC, Stefan Koch 
 wrote:
 Good day,
 Please let know what you think.
Ugh typo.
static immutable ed = cast(EnumDeclaration)nodeFromName(E);
is supposed to be: `static immutable ed = cast(EnumDeclaration)nodeFromName("E");`
What about E.stringof? Instead of hardcoding names :) Not sure if stringof will return E in all cases, so obviously only if it works.
E stringof would return the name of the type; In simple cases and garbage in others. Whereas the name E always refers to the type used in the toString template. Also "E" is less typing than E.stringof
Yeah I figured it wouldn't work that easily. In this case yeah "E" wouldn't be a problem but if it was "ThisTypeName" you might end up with a typo.
Sep 27 2021
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Monday, 27 September 2021 at 07:32:48 UTC, bauss wrote:
 Yeah I figured it wouldn't work that easily.

 In this case yeah "E" wouldn't be a problem but if it was 
 "ThisTypeName" you might end up with a typo.
Yes, but you can typo ThisTypeName whether you type it with quotes around it or without. It's still an identifier. Which may not be Identifying anything if it's mistyped. The reason why I am using a string is that I wanted to avoid having to introduce a special expression. see c++ `reflexpr`
Sep 27 2021
parent reply WebFreak001 <d.forum webfreak.org> writes:
On Monday, 27 September 2021 at 08:39:45 UTC, Stefan Koch wrote:
 On Monday, 27 September 2021 at 07:32:48 UTC, bauss wrote:
 Yeah I figured it wouldn't work that easily.

 In this case yeah "E" wouldn't be a problem but if it was 
 "ThisTypeName" you might end up with a typo.
Yes, but you can typo ThisTypeName whether you type it with quotes around it or without. It's still an identifier. Which may not be Identifying anything if it's mistyped. The reason why I am using a string is that I wanted to avoid having to introduce a special expression. see c++ `reflexpr`
If it's mistyped, the compiler will complain that it doesn't exist When it's an identifier, IDE refactorings (automated renaming) will find it, while it wouldn't find it in a string, especially the more generic the name is (which is common for template types `T`) `nameof(Foo.T)` it also just returns `"T"`
Sep 27 2021
next sibling parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Monday, 27 September 2021 at 13:12:32 UTC, WebFreak001 wrote:

 If it's mistyped, the compiler will complain that it doesn't 
 exist
core.reflect will tell you that you tried to resolve a name which does not exist as well.
 When it's an identifier, IDE refactorings (automated renaming) 
 will find it, while it wouldn't find it in a string, especially 
 the more generic the name is (which is common for template 
 types `T`)


 `nameof(Foo.T)` it also just returns `"T"`
That's valid. I have to think about what to do about that. Maybe remove the "" for the refactoring? a simple search for `nodeFromName\(\"$ID\"\)` maybe? It's the only primitive in code reflect which does this.
Sep 27 2021
next sibling parent reply russhy <russhy gmail.com> writes:
using traits:

```D
string enum_to_str(E)(E v) if (is(E == enum))
{
     final switch (v) with(E)
     {
         static foreach (m; __traits(allMembers, E))
         {
     case mixin(m):
             return m;
         }
     }
}
```

core.reflect is nicer than traits because you actually get to use 
actual D code

But the casting is kinda ugly, and it gives me java nightmares.. 
so the C++ actually feels much better
Sep 27 2021
parent Stefan Koch <uplink.coder googlemail.com> writes:
On Monday, 27 September 2021 at 22:51:01 UTC, russhy wrote:
 using traits:

 ```D
 string enum_to_str(E)(E v) if (is(E == enum))
 {
     final switch (v) with(E)
     {
         static foreach (m; __traits(allMembers, E))
         {
     case mixin(m):
             return m;
         }
     }
 }
 ```

 core.reflect is nicer than traits because you actually get to 
 use actual D code

 But the casting is kinda ugly, and it gives me java 
 nightmares.. so the C++ actually feels much better
Yes the casting isn't great but all of that can be hidden with more library code. The class oriented design of core.reflect is the way it is because it mirrors internals rather closely at this point. I am open for improvement suggestions.
Sep 28 2021
prev sibling parent reply WebFreak001 <d.forum webfreak.org> writes:
On Monday, 27 September 2021 at 15:17:39 UTC, Stefan Koch wrote:
 On Monday, 27 September 2021 at 13:12:32 UTC, WebFreak001 wrote:

 If it's mistyped, the compiler will complain that it doesn't 
 exist
core.reflect will tell you that you tried to resolve a name which does not exist as well.
 When it's an identifier, IDE refactorings (automated renaming) 
 will find it, while it wouldn't find it in a string, 
 especially the more generic the name is (which is common for 
 template types `T`)


 `nameof(Foo.T)` it also just returns `"T"`
That's valid. I have to think about what to do about that. Maybe remove the "" for the refactoring? a simple search for `nodeFromName\(\"$ID\"\)` maybe? It's the only primitive in code reflect which does this.
maybe for `nodeFromName("T")` leave it unsolved but there could also be a `nodeFrom!T` which could additionally check for the type of T and return the correct node type (like EnumDeclaration from enums) This would additionally remove the need to do casts (and potentially mess up)
Sep 28 2021
parent Stefan Koch <uplink.coder googlemail.com> writes:
On Tuesday, 28 September 2021 at 07:10:43 UTC, WebFreak001 wrote:
 maybe for `nodeFromName("T")` leave it unsolved but there could 
 also be a `nodeFrom!T` which could additionally check for the 
 type of T and return the correct node type (like 
 EnumDeclaration from enums)

 This would additionally remove the need to do casts (and 
 potentially mess up)
I can provide a `NodeFromAlias`. But I don't want to promote such use. I went through some of trouble to avoid static polymorphism. I have to admit it is though it is tempting to chose the more convenient. `node!bla` syntax.
Sep 28 2021
prev sibling parent reply bauss <jj_1337 live.dk> writes:
On Monday, 27 September 2021 at 13:12:32 UTC, WebFreak001 wrote:
 On Monday, 27 September 2021 at 08:39:45 UTC, Stefan Koch wrote:
 On Monday, 27 September 2021 at 07:32:48 UTC, bauss wrote:
 Yeah I figured it wouldn't work that easily.

 In this case yeah "E" wouldn't be a problem but if it was 
 "ThisTypeName" you might end up with a typo.
Yes, but you can typo ThisTypeName whether you type it with quotes around it or without. It's still an identifier. Which may not be Identifying anything if it's mistyped. The reason why I am using a string is that I wanted to avoid having to introduce a special expression. see c++ `reflexpr`
If it's mistyped, the compiler will complain that it doesn't exist When it's an identifier, IDE refactorings (automated renaming) will find it, while it wouldn't find it in a string, especially the more generic the name is (which is common for template types `T`) `nameof(Foo.T)` it also just returns `"T"`
Yeah, I really wish we had an alternative to stringof like nameof. I often forgot that aliases don't work well with it, as displayed here :)
Sep 27 2021
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Tuesday, 28 September 2021 at 06:43:39 UTC, bauss wrote:
 Yeah, I really wish we had an alternative to stringof like 
 nameof. I often forgot that aliases don't work well with it, as 
 displayed here :)
It is called __traits(identifier) .stringof should never be used outside of debugging messages.
Sep 28 2021
next sibling parent reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Tuesday, 28 September 2021 at 11:45:37 UTC, Adam D Ruppe wrote:
 It is called

 __traits(identifier)

 .stringof should never be used outside of debugging messages.
Why is `.stringof` worse than `__traits(identifier)`?
Sep 28 2021
next sibling parent Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Tuesday, 28 September 2021 at 12:32:04 UTC, Per Nordlöw wrote:
 On Tuesday, 28 September 2021 at 11:45:37 UTC, Adam D Ruppe 
 wrote:
 It is called

 __traits(identifier)

 .stringof should never be used outside of debugging messages.
Why is `.stringof` worse than `__traits(identifier)`?
Because traits identifier is well defined to return only the id of the subject, while stringof can return more than id. It can for example return the expression as a string.
Sep 28 2021
prev sibling parent reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Tuesday, 28 September 2021 at 12:32:04 UTC, Per Nordlöw wrote:
 .stringof should never be used outside of debugging messages.
Why? And in what cases is`.stringof` worse than `__traits(identifier)`?
Note that `.stringof` works in cases where `__traits(identifier)` doesn't, such as in ```d alias S = string; pragma(msg, S.stringof); // ok, print `string` pragma(msg, __traits(identifier, S)); // fails ``` .
Sep 28 2021
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Tuesday, 28 September 2021 at 12:38:52 UTC, Per Nordlöw wrote:
 Note that `.stringof` works in cases where 
 `__traits(identifier)` doesn't, such as in
That's because a type has no identifier. And this is good anyway because there's never a good reason to get a type as a string. It is a bug waiting to happen any time someone writes that, so making it an error is a good thing.
Sep 28 2021
parent reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Tuesday, 28 September 2021 at 12:48:08 UTC, Adam D Ruppe wrote:
 That's because a type has no identifier. And this is good 
 anyway because there's never a good reason to get a type as a 
 string. It is a bug waiting to happen any time someone writes 
 that, so making it an error is a good thing.
Can you elaborate on why you consider this being a bug?
Sep 28 2021
parent Adam D Ruppe <destructionator gmail.com> writes:
On Tuesday, 28 September 2021 at 12:53:36 UTC, Per Nordlöw wrote:
 Can you elaborate on why you consider this being a bug?
https://forum.dlang.org/post/fbcltjuysmjrxmebeeva forum.dlang.org https://stackoverflow.com/questions/32615733/struct-composition-with-mixin-and-templates/32621854#32621854
Sep 28 2021
prev sibling parent reply bauss <jj_1337 live.dk> writes:
On Tuesday, 28 September 2021 at 11:45:37 UTC, Adam D Ruppe wrote:
 On Tuesday, 28 September 2021 at 06:43:39 UTC, bauss wrote:
 Yeah, I really wish we had an alternative to stringof like 
 nameof. I often forgot that aliases don't work well with it, 
 as displayed here :)
It is called __traits(identifier) .stringof should never be used outside of debugging messages.
__traits(identifier) doesn't work either. See: https://run.dlang.io/is/9cDdra
Sep 28 2021
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Tuesday, 28 September 2021 at 13:51:55 UTC, bauss wrote:
 __traits(identifier) doesn't work either.

 See:

 https://run.dlang.io/is/9cDdra
That's doing exactly what it is supposed to do. What did you expect and why do you want that?
Sep 28 2021
parent bauss <jj_1337 live.dk> writes:
On Tuesday, 28 September 2021 at 13:59:22 UTC, Adam D Ruppe wrote:
 On Tuesday, 28 September 2021 at 13:51:55 UTC, bauss wrote:
 __traits(identifier) doesn't work either.

 See:

 https://run.dlang.io/is/9cDdra
That's doing exactly what it is supposed to do. What did you expect and why do you want that?
Yeah but the point in this case is to get "a" as a string. That's what I meant in my original comment and that's also what's being discussed with nameof.
Sep 28 2021