Thread overview | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
June 13, 2015 __traits getMember is context sensetive? | ||||
---|---|---|---|---|
| ||||
Hey, i am trying to wrap my head around __traits. One thing i just do not understand is following: struct S{ string member1; int member2; } void main(string[] args) { foreach(typeStr; __traits(allMembers, S)) { auto tp = __traits(getMember, S, typeStr); static if (__traits(isArithmetic, tp)) writeln(typeStr ~ " is Arithmetic"); } } Does not compile. "main.d(15): Error: need 'this' for 'member1' of type 'string'" But if the inner part of the foreach-loop is changed to: static if (__traits(isArithmetic, __traits(getMember, S, typeStr))) writeln(typeStr ~ " is Arithmetic"); it compiles and does exactly what i expect it to do. If i understand it correctly __traits(getMember returns a reference to that member, so i get why i shouldn't be able to use it with the class instead of an instance of a class. But why does it work if it is nested inside a __traits call? |
June 13, 2015 Re: __traits getMember is context sensetive? | ||||
---|---|---|---|---|
| ||||
Posted in reply to JDemler | On Saturday, 13 June 2015 at 10:01:45 UTC, JDemler wrote:
> Hey,
>
> i am trying to wrap my head around __traits.
>
> One thing i just do not understand is following:
>
> struct S{
> string member1;
> int member2;
> }
>
> void main(string[] args)
> {
> foreach(typeStr; __traits(allMembers, S))
> {
> auto tp = __traits(getMember, S, typeStr);
> static if (__traits(isArithmetic, tp))
> writeln(typeStr ~ " is Arithmetic");
> }
> }
>
> Does not compile. "main.d(15): Error: need 'this' for 'member1'
> of type 'string'"
>
> But if the inner part of the foreach-loop is changed to:
>
> static if (__traits(isArithmetic, __traits(getMember, S,
> typeStr)))
> writeln(typeStr ~ " is Arithmetic");
>
> it compiles and does exactly what i expect it to do.
>
> If i understand it correctly __traits(getMember returns a
> reference to that member, so i get why i shouldn't be able to use
> it with the class instead of an instance of a class.
>
> But why does it work if it is nested inside a __traits call?
Try `alias` instead of `auto`:
struct S{
string member1;
int member2;
}
alias I(Args...) = Args;
void main(string[] args)
{
import std.stdio;
foreach(typeStr; __traits(allMembers, S))
{
alias tp = I!(__traits(getMember, S, typeStr));
static if (__traits(isArithmetic, tp))
writeln(typeStr ~ " is Arithmetic");
}
}
`auto` declares a variable, which in this case will probably contain a delegate to that member.
The workaround with `I` is needed because of a syntactic limitation: `alias tp = __traits(...);` is currently not allowed by the grammar.
|
June 13, 2015 Re: __traits getMember is context sensetive? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc Schütz | On Saturday, 13 June 2015 at 10:26:06 UTC, Marc Schütz wrote:
> On Saturday, 13 June 2015 at 10:01:45 UTC, JDemler wrote:
>> Hey,
>>
>> i am trying to wrap my head around __traits.
>>
>> One thing i just do not understand is following:
>>
>> struct S{
>> string member1;
>> int member2;
>> }
>>
>> void main(string[] args)
>> {
>> foreach(typeStr; __traits(allMembers, S))
>> {
>> auto tp = __traits(getMember, S, typeStr);
>> static if (__traits(isArithmetic, tp))
>> writeln(typeStr ~ " is Arithmetic");
>> }
>> }
>>
>> Does not compile. "main.d(15): Error: need 'this' for 'member1'
>> of type 'string'"
>>
>> But if the inner part of the foreach-loop is changed to:
>>
>> static if (__traits(isArithmetic, __traits(getMember, S,
>> typeStr)))
>> writeln(typeStr ~ " is Arithmetic");
>>
>> it compiles and does exactly what i expect it to do.
>>
>> If i understand it correctly __traits(getMember returns a
>> reference to that member, so i get why i shouldn't be able to use
>> it with the class instead of an instance of a class.
>>
>> But why does it work if it is nested inside a __traits call?
>
> Try `alias` instead of `auto`:
>
> struct S{
> string member1;
> int member2;
> }
>
> alias I(Args...) = Args;
>
> void main(string[] args)
> {
> import std.stdio;
> foreach(typeStr; __traits(allMembers, S))
> {
> alias tp = I!(__traits(getMember, S, typeStr));
> static if (__traits(isArithmetic, tp))
> writeln(typeStr ~ " is Arithmetic");
> }
> }
>
> `auto` declares a variable, which in this case will probably contain a delegate to that member.
>
> The workaround with `I` is needed because of a syntactic limitation: `alias tp = __traits(...);` is currently not allowed by the grammar.
Thank you. I tried alias but encountered the limitation mentioned.
|
June 13, 2015 Re: __traits getMember is context sensetive? | ||||
---|---|---|---|---|
| ||||
Posted in reply to JDemler | On Saturday, 13 June 2015 at 10:01:45 UTC, JDemler wrote:
> Hey,
>
> i am trying to wrap my head around __traits.
>
> One thing i just do not understand is following:
>
> struct S{
> string member1;
> int member2;
> }
>
> void main(string[] args)
> {
> foreach(typeStr; __traits(allMembers, S))
> {
> auto tp = __traits(getMember, S, typeStr);
> static if (__traits(isArithmetic, tp))
> writeln(typeStr ~ " is Arithmetic");
> }
> }
>
> Does not compile. "main.d(15): Error: need 'this' for 'member1'
> of type 'string'"
>
> But if the inner part of the foreach-loop is changed to:
>
> static if (__traits(isArithmetic, __traits(getMember, S,
> typeStr)))
> writeln(typeStr ~ " is Arithmetic");
>
> it compiles and does exactly what i expect it to do.
>
> If i understand it correctly __traits(getMember returns a
> reference to that member, so i get why i shouldn't be able to use
> it with the class instead of an instance of a class.
>
> But why does it work if it is nested inside a __traits call?
"auto tp" is treating a runtime variable, but you don't have an actual instance of S. What you want is an alias of the symbol without creating an instance.
Unfortunately alias tp = __traits(getMember, S, typeStr); doesn't work, but if you steal* Alias from std.typetuple(or std.meta, if you're running a very recent dmd build) then you can do
alias tp = Alias!(__traits(getMember, S, typeStr));
and then it will work for you.
*for some reason it's not public, but it's very short and simple:
template Alias(alias a)
{
static if (__traits(compiles, { alias x = a; }))
alias Alias = a;
else static if (__traits(compiles, { enum x = a; }))
enum Alias = a;
else
static assert(0, "Cannot alias " ~ a.stringof);
}
// types and tuples
template Alias(a...)
{
alias Alias = a;
}
unittest
{
enum abc = 1;
static assert(__traits(compiles, { alias a = Alias!(123); }));
static assert(__traits(compiles, { alias a = Alias!(abc); }));
static assert(__traits(compiles, { alias a = Alias!(int); }));
static assert(__traits(compiles, { alias a = Alias!(1,abc,int); }));
}
|
June 13, 2015 Re: __traits getMember is context sensetive? | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Colvin Attachments: | On Sat, 13 Jun 2015 10:36:39 +0000, John Colvin wrote:
> *for some reason it's not public, but it's very short and simple:
it's funny how many useful things are there in Phobos, carefully hidden from user. i believe each D book should include an advice like this: "to fully learn what you can do in D out-of-the-box, carefully read druntime and Phobos sources. you'll find many gems there. but tell noone about your discoveries, neophytes should not get the Secret Knowledge!" ;-)
|
June 13, 2015 Re: __traits getMember is context sensetive? | ||||
---|---|---|---|---|
| ||||
Posted in reply to ketmar | I have another one :) module test; struct S{ string member1; int member2; } string test(string[] a) { const S s = { member1:"It is also important to go to Mars!"}; const string y = a[0]; return y; } void main() { enum e = ["member1","member2"]; pragma(msg, e[0]); pragma(msg, test(e)); } Compiles, works fine while module test; struct S{ string member1; int member2; } string test(string[] a) { const S s = { member1:"It is also important to go to Mars!"}; const string y = a[0]; return __traits(getMember, s, y); } void main() { enum e = ["member1","member2"]; pragma(msg, e[0]); pragma(msg, test(e)); } spits out following: test.d(11): Error: variable a cannot be read at compile time test.d(12): while evaluating y.init test.d(12): Error: string expected as second argument of __traits getMember instead of __error test.d(12): Error: cannot implicitly convert expression (false) of type bool to string member1 test.d(19): Error: CTFE failed because of previous errors in test test.d(19): while evaluating pragma(msg, test(["member1", "member2"])) If i use "member1" directly it works. What am I missing here? Thanks for your help |
June 13, 2015 Re: __traits getMember is context sensetive? | ||||
---|---|---|---|---|
| ||||
Posted in reply to JDemler | On Saturday, 13 June 2015 at 23:51:32 UTC, JDemler wrote:
> I have another one :)
>
> module test;
>
> struct S{
> string member1;
> int member2;
> }
>
> string test(string[] a)
> {
> const S s = { member1:"It is also important to go to Mars!"};
> const string y = a[0];
> return y;
> }
>
> void main()
> {
> enum e = ["member1","member2"];
> pragma(msg, e[0]);
> pragma(msg, test(e));
> }
>
> Compiles, works fine while
>
> module test;
>
> struct S{
> string member1;
> int member2;
> }
>
> string test(string[] a)
> {
> const S s = { member1:"It is also important to go to Mars!"};
> const string y = a[0];
> return __traits(getMember, s, y);
> }
>
> void main()
> {
> enum e = ["member1","member2"];
> pragma(msg, e[0]);
> pragma(msg, test(e));
> }
>
> spits out following:
>
> test.d(11): Error: variable a cannot be read at compile time
> test.d(12): while evaluating y.init
> test.d(12): Error: string expected as second argument of __traits getMember instead of __error
> test.d(12): Error: cannot implicitly convert expression (false) of type bool to string
> member1
> test.d(19): Error: CTFE failed because of previous errors in test
> test.d(19): while evaluating pragma(msg, test(["member1", "member2"]))
>
> If i use "member1" directly it works.
>
> What am I missing here?
>
> Thanks for your help
After a bit of rethinking:
I guess the compiler goes through 2 loops:
the first resolves __traits, the second does ctfe.
That would explain this behavior. "a" is not present to the compiler while it tries to resolve my __traits call, but will be present in case of ctfe.
Is there a workaround for that?
|
June 14, 2015 Re: __traits getMember is context sensetive? | ||||
---|---|---|---|---|
| ||||
Posted in reply to JDemler Attachments: | On Sat, 13 Jun 2015 23:55:53 +0000, JDemler wrote:
> After a bit of rethinking:
>
> I guess the compiler goes through 2 loops:
> the first resolves __traits, the second does ctfe.
>
> That would explain this behavior. "a" is not present to the compiler while it tries to resolve my __traits call, but will be present in case of ctfe.
the thing is that `a` (and `s` for that matter) is a *runtime* variable. even if you can see that it will not change and effectively a constant, compiler doesn't see that and doesn't assume that it can use such constants in CTFE.
the difference is like this:
enum s0 = "string0"; // compile time constant
string s1 = "string1"; // runtime constant
compiler doesn't do data flow analysis to prove that s1 will never change and it can be used as compile time constant, it simply plays a crybaby here, complaining that it can't read runtime variable value in compile time.
here's what you can do instead:
immutable S s = { member1:"It is also important to go to Mars!"};
template test(string[] a) {
enum y = a[0];
enum test = __traits(getMember, s, y);
}
void main () {
enum e = ["member1","member2"];
pragma(msg, e[0]);
pragma(msg, test!(e));
}
|
June 14, 2015 Re: __traits getMember is context sensetive? | ||||
---|---|---|---|---|
| ||||
Posted in reply to JDemler Attachments: | oh, seems that i managed to make everything even less understandable... |
June 14, 2015 Re: __traits getMember is context sensetive? | ||||
---|---|---|---|---|
| ||||
Posted in reply to ketmar | On Sunday, 14 June 2015 at 05:52:00 UTC, ketmar wrote:
> oh, seems that i managed to make everything even less understandable...
Your code works perfectly and makes at least some sense to me. Thank you.
If i understand it correctly: __traits-time = templateinstatiation-time = pragma-time before ctfe-time?
|
Copyright © 1999-2021 by the D Language Foundation