Thread overview
Determine if a type if derived from a template parameter
Apr 10, 2019
Alex
Apr 10, 2019
rikki cattermole
Apr 10, 2019
Adam D. Ruppe
Apr 10, 2019
Alex
Apr 11, 2019
Alex
Apr 11, 2019
Basile B.
Apr 11, 2019
Alex
Apr 11, 2019
Simen Kjærås
Apr 11, 2019
Alex
April 10, 2019
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.


April 11, 2019
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;
}
April 10, 2019
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.
April 10, 2019
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]
April 11, 2019
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...
April 11, 2019
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.
April 11, 2019
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.


April 11, 2019
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 generics found in Java and C#, and this power comes with some cost.

--
  Simen
April 11, 2019
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 generics found in Java and C#, and this power comes with some 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?]