Thread overview | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
October 25, 2014 Generating code based on UDA | ||||
---|---|---|---|---|
| ||||
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 |
October 25, 2014 Re: Generating code based on UDA | ||||
---|---|---|---|---|
| ||||
Posted in reply to Rares Pop | 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...
|
October 25, 2014 Re: Generating code based on UDA | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | 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...
|
October 25, 2014 Re: Generating code based on UDA | ||||
---|---|---|---|---|
| ||||
Posted in reply to Rares Pop | 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,
> Rares
Very 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.
|
October 25, 2014 Re: Generating code based on UDA | ||||
---|---|---|---|---|
| ||||
Posted in reply to Rares Pop | 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.
|
October 25, 2014 Re: Generating code based on UDA | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | 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:
>> 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.
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?
|
October 25, 2014 Re: Generating code based on UDA | ||||
---|---|---|---|---|
| ||||
Posted in reply to Rares Pop | On 10/25/2014 07:45 AM, Rares Pop wrote: > 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: >>> 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. > > 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)) > { import std.string; > 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 |
October 25, 2014 Re: Generating code based on UDA | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | Ali, Many thanks for your help. What is the rationale for mixin(fullName) ? |
October 25, 2014 Re: Generating code based on UDA | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | 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 |
October 25, 2014 Re: Generating code based on UDA | ||||
---|---|---|---|---|
| ||||
Posted in reply to Rares Pop | I've uploaded the code here: https://github.com/fusionbeam/infuse |
Copyright © 1999-2021 by the D Language Foundation