Jump to page: 1 2
Thread overview
Generating code based on UDA
Oct 25, 2014
Rares Pop
Oct 25, 2014
Adam D. Ruppe
Oct 25, 2014
Rares Pop
Oct 25, 2014
Adam D. Ruppe
Oct 25, 2014
Rares Pop
Oct 25, 2014
Ali Çehreli
Oct 25, 2014
Rares Pop
Oct 25, 2014
Rares Pop
Oct 25, 2014
Rares Pop
Oct 25, 2014
Rares Pop
Oct 25, 2014
Ali Çehreli
Oct 26, 2014
Rares Pop
Oct 26, 2014
Rares Pop
Oct 25, 2014
Shammah Chancellor
October 25, 2014
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
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
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
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
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
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
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
Ali,
Many thanks for your help.

What is the rationale for mixin(fullName) ?




October 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
October 25, 2014
I've uploaded the code here:
https://github.com/fusionbeam/infuse
« First   ‹ Prev
1 2