digitalmars.D.learn - Generating code based on UDA
- Rares Pop (22/22) Oct 25 2014 Hello everyone,
- Adam D. Ruppe (2/4) Oct 25 2014 Yes, and copy/pasting that works for me...
- Rares Pop (3/7) Oct 25 2014 Thanks for the quick response.
- Adam D. Ruppe (6/7) Oct 25 2014 I literally copied the code in your post (and fixed a missing
- Rares Pop (57/64) Oct 25 2014 Taking this one step further, it looks like the attributes are
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (71/114) Oct 25 2014 You must mixin fullName:
- Rares Pop (3/3) Oct 25 2014 Ali,
- Rares Pop (16/16) Oct 25 2014 Ali,
- Rares Pop (2/2) Oct 25 2014 I've uploaded the code here:
- Rares Pop (3/5) Oct 25 2014 compiling with ldc2 exhibits the same behaviour.
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (17/24) Oct 25 2014 __traits(getAttributes) requires a symbol but fullName is a string.
- Shammah Chancellor (12/38) Oct 25 2014 Very much possible. Since I don't see what your template is doing, I'm
Hello everyone, I am trying to understand UDA traits scoping while mixing in code. Aiming to generate code based on UDA I wonder if the following is possible: class A { Inject Logger logger; Inject SomeOtherClass dependency; mixin injections!(A) ... } In "injections" function I want to iterate through members annotated with the Inject attribute and generate some specific code. So far in my attempts the compiler complains about unknown identifier A. Should the A class be available to the compiler at the time of the mixin invocation? Thanks for your help, Rares
Oct 25 2014
On Saturday, 25 October 2014 at 13:37:56 UTC, Rares Pop wrote:Aiming to generate code based on UDA I wonder if the following is possible:Yes, and copy/pasting that works for me...
Oct 25 2014
Thanks for the quick response. What do you mean by copy/pasting ? On Saturday, 25 October 2014 at 13:40:56 UTC, Adam D. Ruppe wrote:On Saturday, 25 October 2014 at 13:37:56 UTC, Rares Pop wrote:Aiming to generate code based on UDA I wonder if the following is possible:Yes, and copy/pasting that works for me...
Oct 25 2014
On Saturday, 25 October 2014 at 13:45:29 UTC, Rares Pop wrote:What do you mean by copy/pasting ?I literally copied the code in your post (and fixed a missing semicolon) and got it to compile. Passing A as an argument to injections should work. You can also use this and typeof(this) inside the injections template code to access the class. It should all work.
Oct 25 2014
On Saturday, 25 October 2014 at 13:53:35 UTC, Adam D. Ruppe wrote:On Saturday, 25 October 2014 at 13:45:29 UTC, Rares Pop wrote:Taking this one step further, it looks like the attributes are not available at the mixin scope. Here is my code: ------ struct Inject { // immutable Scope scoped; } static string injections(T)() { pragma(msg, "injections for : ", T); string result; foreach(member; __traits(allMembers,T)) { enum fullName = format("%s.%s", T.stringof, member); pragma(msg, "member: ", fullName); auto attributes = __traits(getAttributes, fullName); enum dbg_msg = format ("%s attributes are %s", fullName, attributes.stringof); pragma(msg, dbg_msg); foreach(attr;attributes){ pragma(msg, "Checking attribute", attr); } } return result; } class A { this(){ } } class B { Inject A a; mixin(injections!(B)); } --- when compiling this code this is the output I get: ---- Compiling using dmd... injections for : B member: B.a B.a attributes are tuple() member: B.toString B.toString attributes are tuple() member: B.toHash B.toHash attributes are tuple() member: B.opCmp B.opCmp attributes are tuple() member: B.opEquals B.opEquals attributes are tuple() member: B.Monitor B.Monitor attributes are tuple() member: B.factory B.factory attributes are tuple() ------ B.a attributes are an empty tuple even though the member is annotated with Inject. Any ideas why?What do you mean by copy/pasting ?I literally copied the code in your post (and fixed a missing semicolon) and got it to compile. Passing A as an argument to injections should work. You can also use this and typeof(this) inside the injections template code to access the class. It should all work.
Oct 25 2014
On 10/25/2014 07:45 AM, Rares Pop wrote:On Saturday, 25 October 2014 at 13:53:35 UTC, Adam D. Ruppe wrote:import std.string;On Saturday, 25 October 2014 at 13:45:29 UTC, Rares Pop wrote:Taking this one step further, it looks like the attributes are not available at the mixin scope. Here is my code: ------ struct Inject { // immutable Scope scoped; } static string injections(T)() { pragma(msg, "injections for : ", T); string result; foreach(member; __traits(allMembers,T)) {What do you mean by copy/pasting ?I literally copied the code in your post (and fixed a missing semicolon) and got it to compile. Passing A as an argument to injections should work. You can also use this and typeof(this) inside the injections template code to access the class. It should all work.enum fullName = format("%s.%s", T.stringof, member); pragma(msg, "member: ", fullName); auto attributes = __traits(getAttributes, fullName);You must mixin fullName: auto attributes = __traits(getAttributes, mixin(fullName));enum dbg_msg = format ("%s attributes are %s", fullName, attributes.stringof); pragma(msg, dbg_msg); foreach(attr;attributes){Replace the body of this foreach with the following: pragma(msg, "Checking attribute of type", typeof(attr)); static if (is (typeof(attr) == Inject)) { pragma(msg, "Found one"); // Let's inject something: result ~= q{ int foo() { return 42; } }; }pragma(msg, "Checking attribute", attr); } } return result; } class A { this(){ } } class B { Inject A a;For an unknown reason to me, that UDA wants an Inject object, not the type itself: Inject() A a; I am puzzled with that...mixin(injections!(B)); }Then it works with the following main: void main() { auto b = new B(); assert(b.foo() == 42); // It worked! :) } Here is the complete program: struct Inject { // immutable Scope scoped; } static string injections(T)() { pragma(msg, "injections for : ", T); string result; foreach(member; __traits(allMembers,T)) { import std.string; enum fullName = format("%s.%s", T.stringof, member); pragma(msg, "member: ", fullName); auto attributes = __traits(getAttributes, mixin(fullName)); enum dbg_msg = format ("%s attributes are %s", fullName, attributes.stringof); pragma(msg, dbg_msg); foreach(attr;attributes){ pragma(msg, "Checking attribute of type", typeof(attr)); static if (is (typeof(attr) == Inject)) { pragma(msg, "Found one"); // Let's inject something: result ~= q{ int foo() { return 42; } }; } } } return result; } class A { this(){ } } class B { Inject() A a; mixin(injections!(B)); } void main() { auto b = new B(); assert(b.foo() == 42); // It worked! :) } Ali
Oct 25 2014
Ali, Many thanks for your help. What is the rationale for mixin(fullName) ?
Oct 25 2014
Ali, Many thanks for your help. Indeed it worked. What is the rationale behind the mixin(fullName) ? However, in my project the injections function, the Inject UDA struct and some other dependencies are defined in a library (libinfuse). In this format the compiler gives the undefined identifier error I was mentioning in my first post. "source/infuse/injector.d-mixin-148(148): Error: undefined identifier B" From what I read in the documentation, source mixins should have the instantiation scope. Is this a dmd compiler bug? Thanks again for your input guys, Rares
Oct 25 2014
I've uploaded the code here: https://github.com/fusionbeam/infuse
Oct 25 2014
On Saturday, 25 October 2014 at 16:01:29 UTC, Rares Pop wrote:I've uploaded the code here: https://github.com/fusionbeam/infusecompiling with ldc2 exhibits the same behaviour. 'Error: undefined identifier B'
Oct 25 2014
On 10/25/2014 08:56 AM, Rares Pop wrote:Indeed it worked. What is the rationale behind the mixin(fullName) ?__traits(getAttributes) requires a symbol but fullName is a string. Mixing it in as code fulfills the requirement.However, in my project the injections function, the Inject UDA struct and some other dependencies are defined in a library (libinfuse).I am afraid it needs to be changed. :-/In this format the compiler gives the undefined identifier error I was mentioning in my first post. "source/infuse/injector.d-mixin-148(148): Error: undefined identifier B"I found two solutions: a) Do not define 'attributes' at all and use __traits(getAttributes) directly in the foreach loop: foreach (attr; __traits(getAttributes, mixin(fullName))) { b) Define attributes as a typeof of __traits(getAttributes) and use that in the foreach loop: alias attributes = typeof(__traits(getAttributes, mixin(fullName))); foreach (attr; attributes) { I think what happens in both cases is that the entity that we iterate over maintains its TypeTuple'ness without trying to produce a value out of its members.Is this a dmd compiler bug?I don't know but it is very confusing. Ali
Oct 25 2014
I think it is a bug. Executing linked code from a mixin statement should not reduce the scope of the mixin, IMHO. I will file a bug report. On Saturday, 25 October 2014 at 21:35:44 UTC, Ali Çehreli wrote:On 10/25/2014 08:56 AM, Rares Pop wrote:Indeed it worked. What is the rationale behind themixin(fullName) ? __traits(getAttributes) requires a symbol but fullName is a string. Mixing it in as code fulfills the requirement.However, in my project the injections function, the InjectUDA structand some other dependencies are defined in a library(libinfuse). I am afraid it needs to be changed. :-/In this format the compiler gives the undefined identifiererror I wasmentioning in my first post. "source/infuse/injector.d-mixin-148(148): Error: undefinedidentifier B" I found two solutions: a) Do not define 'attributes' at all and use __traits(getAttributes) directly in the foreach loop: foreach (attr; __traits(getAttributes, mixin(fullName))) { b) Define attributes as a typeof of __traits(getAttributes) and use that in the foreach loop: alias attributes = typeof(__traits(getAttributes, mixin(fullName))); foreach (attr; attributes) { I think what happens in both cases is that the entity that we iterate over maintains its TypeTuple'ness without trying to produce a value out of its members.Is this a dmd compiler bug?I don't know but it is very confusing. Ali
Oct 25 2014
I have found the problem. It was the nested mixin that was causing the scope degradation (not sure if that is intended behaviour). The correct way to iterate through members and get their attribute is like this: foreach(member; __traits(allMembers,T)) { enum fullName = format("%s.%s", T.stringof, member); pragma(msg, "member: ", fullName); foreach(attr; __traits(getAttributes, __traits(getMember, T, member))) { ....
Oct 26 2014
On 2014-10-25 13:37:54 +0000, Rares Pop said:Hello everyone, I am trying to understand UDA traits scoping while mixing in code. Aiming to generate code based on UDA I wonder if the following is possible: class A { Inject Logger logger; Inject SomeOtherClass dependency; mixin injections!(A) ... } In "injections" function I want to iterate through members annotated with the Inject attribute and generate some specific code. So far in my attempts the compiler complains about unknown identifier A. Should the A class be available to the compiler at the time of the mixin invocation? Thanks for your help, RaresVery much possible. Since I don't see what your template is doing, I'm going to give it a guess: class A{ mixin injections; } template injections { .... typeof(this); // e.g. foreach( tra; __traits(getAttributes, typeof(this))) } typeof(this) will be A.
Oct 25 2014