www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Determine if a type if derived from a template parameter

reply Alex <AJ gmail.com> writes:
e.g.,

class X(T,S)
{
    T x;
    S y;
}

Somehow determine if x's type is derived from the template 
parameter.

I doubt D has this capability but it would be nice for certain 
things. In my reflect library the types must be specified such as 
Reflect!(X!(int,float)) and ideally I would like to do 
Reflect!(X!(T,S)) to get generic reflection information. This 
helps reduce overhead as one could reflect once on the generic 
type, cache the results, then simply modify the results for 
specifics.
Apr 10 2019
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
void main()
{
     alias Y = X!(int, long);

     static if (is(Y : X!(W, Z), W, Z)) {
         pragma(msg, W, " ", Z);
     }

}

class X(T,S)
{
    T x;
    S y;
}
Apr 10 2019
next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 10 April 2019 at 19:32:49 UTC, rikki cattermole 
wrote:
     alias Y = X!(int, long);

     static if (is(Y : X!(W, Z), W, Z)) {
Yup. And if you don't know the template argument count, you can use a variadic placeholder static if(is(Y : X!(R), R...)) { // you now know that Y is an instance of X, // and R is the parameters that were passed to it } This thread should have been in learn btw.
Apr 10 2019
prev sibling parent reply Alex <AJ gmail.com> writes:
On Wednesday, 10 April 2019 at 19:32:49 UTC, rikki cattermole 
wrote:
 void main()
 {
     alias Y = X!(int, long);

     static if (is(Y : X!(W, Z), W, Z)) {
         pragma(msg, W, " ", Z);
     }

 }

 class X(T,S)
 {
    T x;
    S y;
 }
That is not what I mean. What I mean is to get not the type, but the ID for the type from for another id. class X(T,S) { T x; S y; } One has x and wants to know x's generic type, which is T in this case, not the type T is "holding". e.g., certain traits returns things that might ultimately be derived from using a template parameter. They return the actual type though rather than the name. Your example will return int and long, I actually would want it to return T and S, in some sense. For example, a difficult way to do what I want, but easy in principle, would be to read the source code, parse it, and get the parameter name from the source. So, hypothetically: TemplateNameOf!(X!(int,long).x) == "T" It would return the template parameter name for anything that was defined a template parameter. Another hypothetical: Suppose one wanted to rebuild the class X above, when one reflected to get the members, it would be impossible to know which parameter was used for x, if any because traits will return, say, int. It is a similar idea to getting the id's of function parameters. [in that we want the symbols used in the source code]
Apr 10 2019
parent Alex <sascha.orlov gmail.com> writes:
On Wednesday, 10 April 2019 at 23:13:48 UTC, Alex wrote:
 Another hypothetical: Suppose one wanted to rebuild the class X 
 above, when one reflected to get the members, it would be 
 impossible to know which parameter was used for x, if any 
 because traits will return, say, int.
I tried something similar a while ago: https://forum.dlang.org/post/yithkynlyqnejalezixy forum.dlang.org What I ended up with is: I put the content of the part to rebuild into a (parametrized) mixin template. And at each place, where I wanted to rebuild this part I mixed it in. Pro: the mixin template forces me to provide checked template parameter Con: I tried to factorize the parts by hand and it wasn't very convenient. At the very end, I needed it in too few places, to continue to pursue this strategy...
Apr 10 2019
prev sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Wednesday, 10 April 2019 at 19:28:38 UTC, Alex wrote:
 e.g.,

 class X(T,S)
 {
    T x;
    S y;
 }

 Somehow determine if x's type is derived from the template 
 parameter.

 I doubt D has this capability but it would be nice for certain 
 things. In my reflect library the types must be specified such 
 as Reflect!(X!(int,float)) and ideally I would like to do 
 Reflect!(X!(T,S)) to get generic reflection information. This 
 helps reduce overhead as one could reflect once on the generic 
 type, cache the results, then simply modify the results for 
 specifics.
You can detect a match between a member and a template argument but you cant know if the match is a coincidence or on purpose. For example: class X(T) { T x; int y; } alias X1 = X!int; here X1.y matches to T but it's a coincidence. The problem that you'll be faced to is that the template parameters are replaced by the symbol or the type.
Apr 11 2019
parent reply Alex <AJ gmail.com> writes:
On Thursday, 11 April 2019 at 08:57:10 UTC, Basile B. wrote:
 On Wednesday, 10 April 2019 at 19:28:38 UTC, Alex wrote:
 e.g.,

 class X(T,S)
 {
    T x;
    S y;
 }

 Somehow determine if x's type is derived from the template 
 parameter.

 I doubt D has this capability but it would be nice for certain 
 things. In my reflect library the types must be specified such 
 as Reflect!(X!(int,float)) and ideally I would like to do 
 Reflect!(X!(T,S)) to get generic reflection information. This 
 helps reduce overhead as one could reflect once on the generic 
 type, cache the results, then simply modify the results for 
 specifics.
You can detect a match between a member and a template argument but you cant know if the match is a coincidence or on purpose. For example: class X(T) { T x; int y; } alias X1 = X!int; here X1.y matches to T but it's a coincidence. The problem that you'll be faced to is that the template parameters are replaced by the symbol or the type.
Yes, which is my point, so one isn't detecting anything. It would be very error prone to assume if a type is the same as the type of the parameter then it is that parameter. This is why I asked if there was a way to do this. The compiler easily knows this information since it has to do the replacement. The only way to hack it is to read the source unless there is some way way in D.
Apr 11 2019
parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Thursday, 11 April 2019 at 10:49:38 UTC, Alex wrote:
 On Thursday, 11 April 2019 at 08:57:10 UTC, Basile B. wrote:
 On Wednesday, 10 April 2019 at 19:28:38 UTC, Alex wrote:
 e.g.,

 class X(T,S)
 {
    T x;
    S y;
 }

 Somehow determine if x's type is derived from the template 
 parameter.

 I doubt D has this capability but it would be nice for 
 certain things. In my reflect library the types must be 
 specified such as Reflect!(X!(int,float)) and ideally I would 
 like to do Reflect!(X!(T,S)) to get generic reflection 
 information. This helps reduce overhead as one could reflect 
 once on the generic type, cache the results, then simply 
 modify the results for specifics.
You can detect a match between a member and a template argument but you cant know if the match is a coincidence or on purpose. For example: class X(T) { T x; int y; } alias X1 = X!int; here X1.y matches to T but it's a coincidence. The problem that you'll be faced to is that the template parameters are replaced by the symbol or the type.
Yes, which is my point, so one isn't detecting anything. It would be very error prone to assume if a type is the same as the type of the parameter then it is that parameter. This is why I asked if there was a way to do this. The compiler easily knows this information since it has to do the replacement. The only way to hack it is to read the source unless there is some way way in D.
There is no way to check this in D today. It's also impossible in the general case, since the relationship between a field and a template parameter can be arbitrarily complex: template RandomType(T) { static if (__DATE__[0] == 'A') alias RandomType = int; else alias RandomType = T; } struct S(T) { RandomType!T a; } // Should print "T" unless __DATE__ starts with an A. // Or should it really? pragma(msg, __traits(getTemplateParameterName, S!string.a)); For this very same reason, it's also impossible to get a generic S where you can simply replace T with the type you want to. Simply put, D's templates are much more powerful than the cost. -- Simen
Apr 11 2019
parent Alex <AJ gmail.com> writes:
On Thursday, 11 April 2019 at 11:45:44 UTC, Simen Kjærås wrote:
 On Thursday, 11 April 2019 at 10:49:38 UTC, Alex wrote:
 On Thursday, 11 April 2019 at 08:57:10 UTC, Basile B. wrote:
 On Wednesday, 10 April 2019 at 19:28:38 UTC, Alex wrote:
 e.g.,

 class X(T,S)
 {
    T x;
    S y;
 }

 Somehow determine if x's type is derived from the template 
 parameter.

 I doubt D has this capability but it would be nice for 
 certain things. In my reflect library the types must be 
 specified such as Reflect!(X!(int,float)) and ideally I 
 would like to do Reflect!(X!(T,S)) to get generic reflection 
 information. This helps reduce overhead as one could reflect 
 once on the generic type, cache the results, then simply 
 modify the results for specifics.
You can detect a match between a member and a template argument but you cant know if the match is a coincidence or on purpose. For example: class X(T) { T x; int y; } alias X1 = X!int; here X1.y matches to T but it's a coincidence. The problem that you'll be faced to is that the template parameters are replaced by the symbol or the type.
Yes, which is my point, so one isn't detecting anything. It would be very error prone to assume if a type is the same as the type of the parameter then it is that parameter. This is why I asked if there was a way to do this. The compiler easily knows this information since it has to do the replacement. The only way to hack it is to read the source unless there is some way way in D.
There is no way to check this in D today. It's also impossible in the general case, since the relationship between a field and a template parameter can be arbitrarily complex: template RandomType(T) { static if (__DATE__[0] == 'A') alias RandomType = int; else alias RandomType = T; } struct S(T) { RandomType!T a; } // Should print "T" unless __DATE__ starts with an A. // Or should it really? pragma(msg, __traits(getTemplateParameterName, S!string.a)); For this very same reason, it's also impossible to get a generic S where you can simply replace T with the type you want to. Simply put, D's templates are much more powerful than the cost. -- Simen
That is not true. Your example proves nothing. RandomType MUST at some point be some type. In your case if I queried the parameter name for A, it would return "" when __DATE__ starts with an A, else it would return RandomType. RandomType could then be queried. The compiler MUST now what the parameter name is. It also is very easy to get this from the source code. If it were impossible it would be impossible for static typing. No matter how complex the obfuscation would be, there must be a deterministic path from the template parameter name to the instantiation of a type with it. If it were not the case how could the compiler possibly figure anything out? The only question is if the compiler tracks this information so it can be reversed. See, no matter how complex you want to create an example, Anything that depends on T to generate a type X used for something, there will be a path from T to X of symbols and the compiler knows exactly what that path is. There ultimately can only be a unique path and so it is reversible. So, you are simply wrong. Trying to overcomplicated it by making it "random" does nothing bot obscure what is really going on. There is nothing random about your code(and nothing random about CT code, it can't be random or it couldn't be compiled). Your code simplifies to only two possibilities: struct S(T) { T a; } or struct S(T) { int a; } and it only depends on what the date is, but no matter what the date is, either a is going to have T or it isn't, and it's only one case depending on the day. So __traits(getTemplateParameterOfMember, S!int.a) == (__DATE__[0] == 'A') ? "" : "T"; and there is nothing non-deterministic about that. [I'm always amazed when someone claims something is impossible... it's nearly impossible to prove anything is impossible. Usually when people make such claims they inevitably are wrong yet many do without any real proof. Maybe it is a flaw in human evolution?]
Apr 11 2019