digitalmars.D.learn - __traits getMember is context sensetive?
- JDemler (27/27) Jun 13 2015 Hey,
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (22/50) Jun 13 2015 Try `alias` instead of `auto`:
- JDemler (2/62) Jun 13 2015 Thank you. I tried alias but encountered the limitation mentioned.
- John Colvin (33/61) Jun 13 2015 "auto tp" is treating a runtime variable, but you don't have an
- ketmar (6/7) Jun 13 2015 it's funny how many useful things are there in Phobos, carefully hidden=...
- JDemler (50/50) Jun 13 2015 I have another one :)
- JDemler (8/59) Jun 13 2015 After a bit of rethinking:
- ketmar (24/32) Jun 13 2015 the thing is that `a` (and `s` for that matter) is a *runtime* variable....
- ketmar (1/1) Jun 13 2015 oh, seems that i managed to make everything even less understandable...=
- JDemler (5/7) Jun 14 2015 Your code works perfectly and makes at least some sense to me.
- John Colvin (11/18) Jun 14 2015 Not really. These things are just (conceptually) done as/when
- JDemler (7/27) Jun 14 2015 If that is the case then i really do not get why my first example
- John Colvin (3/11) Jun 14 2015 An easy to remember rule: If it won't work at runtime, it won't
- ketmar (28/36) Jun 14 2015 not quite right. there is no dedicated "CTFE time". compiler triggers CT...
- anonymous (20/24) Jun 14 2015 One important thing I didn't see stated clearly by anyone in here:
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?
Jun 13 2015
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.
Jun 13 2015
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:Thank you. I tried alias but encountered the limitation mentioned.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.
Jun 13 2015
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); })); }
Jun 13 2015
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=20 from user. i believe each D book should include an advice like this: "to=20 fully learn what you can do in D out-of-the-box, carefully read druntime=20 and Phobos sources. you'll find many gems there. but tell noone about=20 your discoveries, neophytes should not get the Secret Knowledge!" ;-)=
Jun 13 2015
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
Jun 13 2015
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 helpAfter 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?
Jun 13 2015
On Sat, 13 Jun 2015 23:55:53 +0000, JDemler wrote:After a bit of rethinking: =20 I guess the compiler goes through 2 loops: the first resolves __traits, the second does ctfe. =20 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.=20 even if you can see that it will not change and effectively a constant,=20 compiler doesn't see that and doesn't assume that it can use such=20 constants in CTFE. the difference is like this: enum s0 =3D "string0"; // compile time constant string s1 =3D "string1"; // runtime constant compiler doesn't do data flow analysis to prove that s1 will never change=20 and it can be used as compile time constant, it simply plays a crybaby=20 here, complaining that it can't read runtime variable value in compile=20 time. here's what you can do instead: immutable S s =3D { member1:"It is also important to go to Mars!"}; template test(string[] a) { enum y =3D a[0]; enum test =3D __traits(getMember, s, y); } void main () { enum e =3D ["member1","member2"]; pragma(msg, e[0]); pragma(msg, test!(e)); } =
Jun 13 2015
oh, seems that i managed to make everything even less understandable...=
Jun 13 2015
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?
Jun 14 2015
On Sunday, 14 June 2015 at 09:46:56 UTC, JDemler wrote:On Sunday, 14 June 2015 at 05:52:00 UTC, ketmar wrote:Not really. These things are just (conceptually) done as/when they are required. If a template instantiation needs to do ctfe to calculate it's result, it does it. If some code running in ctfe needs the result of a template, it instantiates it. The only distinction you have to think about is compile-time vs run-time, with the caveat that ctfe code is run as if it were run-time, but the result can be used at compile-time. If you imagine ctfe as being "compiling the function, running it, getting the answer and copying it in to your code" then even that distinction goes away and you just have ct vs rt.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?
Jun 14 2015
On Sunday, 14 June 2015 at 10:04:35 UTC, John Colvin wrote:On Sunday, 14 June 2015 at 09:46:56 UTC, JDemler wrote:If that is the case then i really do not get why my first example compiles and my second does not. The compiler sees the pragma(msg, test(e)) and runs test(e). If test uses __traits it does not work if it does not it works. If __traits is just another ctfe function i dont see the difference.On Sunday, 14 June 2015 at 05:52:00 UTC, ketmar wrote:Not really. These things are just (conceptually) done as/when they are required. If a template instantiation needs to do ctfe to calculate it's result, it does it. If some code running in ctfe needs the result of a template, it instantiates it. The only distinction you have to think about is compile-time vs run-time, with the caveat that ctfe code is run as if it were run-time, but the result can be used at compile-time. If you imagine ctfe as being "compiling the function, running it, getting the answer and copying it in to your code" then even that distinction goes away and you just have ct vs rt.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?
Jun 14 2015
On Sunday, 14 June 2015 at 10:16:24 UTC, JDemler wrote:On Sunday, 14 June 2015 at 10:04:35 UTC, John Colvin wrote:An easy to remember rule: If it won't work at runtime, it won't work in ctfe.[...]If that is the case then i really do not get why my first example compiles and my second does not. The compiler sees the pragma(msg, test(e)) and runs test(e). If test uses __traits it does not work if it does not it works. If __traits is just another ctfe function i dont see the difference.
Jun 14 2015
On Sun, 14 Jun 2015 09:46:54 +0000, JDemler wrote:On Sunday, 14 June 2015 at 05:52:00 UTC, ketmar wrote:not quite right. there is no dedicated "CTFE time". compiler triggers CTFE=20 when it needs to, i.e. when it sees something like this: enum myval =3D myfunction(); // or mytemplate!(...) i.e. when it need a value in compile time. the interpreter is invoked, it=20 evaluates (interprets) the given code (function or template=20 instantiation), and then it returns result (or raises an error). so CTFE can occur at any stage of semantic analysis. to be clear: compiler goes (roughly) thru this stages: 1. parsing and building AST. 2. semantic analysis. 3. generating code. at the stage (1) only syntax is checked, and source is converted to=20 internal representation (AST). at the state (2) compiler tries to actually make sense of your code. it=20 deducing types, checking type correctness and such. if it need to=20 instantiate some template, it does that here. it does semantic for each=20 function (note: not for templates or eponymous templates!), one by one. and here compiler may step on something that needs CTFE. it invokes=20 interpreter on this stage. so there is no dedicated "CTFE time", compiler=20 does it while it busy with semantic analysis, on demand. this way it=20 avoids evaluating CTFE values that never used, which is good for compile=20 speed. ;-) pragmas and traits are executed by the very same CTFE engine, on demand=20 too. i.e. when compiler hits pragma or traits during semantic analysis,=20 compiler executes that. overal semantic stage is more complex, of course, but i hope you get the=20 idea.=oh, seems that i managed to make everything even less understandable...=20 Your code works perfectly and makes at least some sense to me. Thank you. =20 If i understand it correctly: __traits-time =3D templateinstatiation-time =3D pragma-time before ctfe-time?
Jun 14 2015
On Sunday, 14 June 2015 at 10:10:51 UTC, ketmar wrote:i.e. when it need a value in compile time. the interpreter is invoked, it evaluates (interprets) the given code (function or template instantiation), and then it returns result (or raises an error).One important thing I didn't see stated clearly by anyone in here: CTFE may run at compile time but it follows the same rules as run time evaluation (plus some restrictions). This means, you can't use dynamic values (e.g. function parameters) in static contexts (e.g. __traits). Example: ---- int f(int x) { if (__ctfe) { enum e = x; /* nope, not even during CTFE */ alias t = some_template!x; /* nope */ pragma(msg, x); /* nope */ } return x; } enum result = f(1); /* CTFE-ing f */ ----
Jun 14 2015
On Sunday, 14 June 2015 at 10:29:09 UTC, anonymous wrote:On Sunday, 14 June 2015 at 10:10:51 UTC, ketmar wrote:So if i want to use parameters in a static context at compile time i have to pass them as template parameters? That would explain my problems. Thanksi.e. when it need a value in compile time. the interpreter is invoked, it evaluates (interprets) the given code (function or template instantiation), and then it returns result (or raises an error).One important thing I didn't see stated clearly by anyone in here: CTFE may run at compile time but it follows the same rules as run time evaluation (plus some restrictions). This means, you can't use dynamic values (e.g. function parameters) in static contexts (e.g. __traits). Example: ---- int f(int x) { if (__ctfe) { enum e = x; /* nope, not even during CTFE */ alias t = some_template!x; /* nope */ pragma(msg, x); /* nope */ } return x; } enum result = f(1); /* CTFE-ing f */ ----
Jun 14 2015
On Sunday, 14 June 2015 at 10:41:24 UTC, JDemler wrote:So if i want to use parameters in a static context at compile time i have to pass them as template parameters?Yes, template parameters are fine.
Jun 14 2015
On Sun, 14 Jun 2015 10:29:08 +0000, anonymous wrote:One important thing I didn't see stated clearly by anyone in here: =20 CTFE may run at compile time but it follows the same rules as run time evaluation (plus some restrictions). =20 This means, you can't use dynamic values (e.g. function parameters) in static contexts (e.g. __traits).yes, i managed to write a wall of text escaping to talk about the main=20 issue of the thread. ;-)=
Jun 14 2015