Proposal: __traits(code, ...) and/or .codeof

luka8088 luka8088 at owave.net
Tue Oct 9 06:04:55 PDT 2012


Is this at least similar to what you had in mind ?

http://dpaste.dzfl.pl/a5dc2875

module program;

import std.stdio;

mixin template BankAccount () {
   public int amount;
   void deposit (int value) { this.amount += value; }
   void withdraw (int value) { this.amount -= value; }
   auto currentAmount () { return this.amount; }
}

mixin template Logger () {
   void deposit (int value) { writeln("User deposited money"); }
   void withdraw (int value) { writeln("User requested money 
back"); }
}

void main () {

   mixin aspect!("bank", BankAccount, Logger);

   bank b1;
   bank b2;

   b1.deposit(10);
   b1.deposit(20);
   b1.withdraw(5);
   writeln("b1.currentAmount: ", b1.currentAmount);

   b2.deposit(50);
   b2.withdraw(40);
   b2.deposit(100);
   writeln("b2.currentAmount: ", b2.currentAmount);

}


// generic code

mixin template aspect (string name, T...) {
   template aspectDispatch (string name, uint n) {
     import convert = std.conv;
     static if (n >= 1)
       enum aspectDispatch = ""
         ~ "import std.traits;\n"
         ~ "static if (__traits(hasMember, data.aspect_" ~ 
convert.to!string(n) ~ ", `" ~ name ~ "`))\n"
         ~ "  static if (!is(ReturnType!(data.aspect_" ~ 
convert.to!string(n) ~ "." ~ name ~ ") == void))\n"
         ~ "    return data.aspect_" ~ convert.to!string(n) ~ "." 
~ name ~ "(arguments);\n"
         ~ "  else\n"
         ~ "    data.aspect_" ~ convert.to!string(n) ~ "." ~ name 
~ "(arguments);\n"
         ~ aspectDispatch!(name, n - 1)
       ;
     else
       enum aspectDispatch = "";
   }
   auto code () {
     import convert = std.conv;
     string ret = ""
       ~ "struct " ~ name ~ " {\n"
       ~ "  struct aspectData {\n"
     ;
     uint i = 0;
     foreach (a; T)
       ret ~= "    mixin " ~ __traits(identifier, a) ~ " aspect_" 
~ convert.to!string(++i) ~ ";\n";
     ret ~= ""
       ~ "  }\n"
       ~ "  aspectData data;\n"
       ~ "  auto opDispatch (string fn, args...) (args arguments) 
{\n"
       ~ "    mixin(aspectDispatch!(fn, " ~ convert.to!string(i) ~ 
"));\n"
       ~ "  }\n"
       ~ "}\n"
     ;
     return ret;
   }
   mixin(code);
}



On Thursday, 22 March 2012 at 16:00:29 UTC, F i L wrote:
> So the discussions about Attributes and Aspect Oriented 
> Programming (AOP) got me thinking... Basically AOP requires 
> injecting code fragments together in a comprehensible way. 
> Similarly, Attributes that go beyond @note (such as @GC.NoScan) 
> need similar ability.
>
> D already has the ability to mixin arbitrary code fragments at 
> compile time, and to process those in useful ways through CTFE. 
> Which rocks. What it lacks is the ability to reflect upon the 
> actual source code due to IO limitations of CTFE. So creating a 
> mixin templates which pieces together a unique object is, to my 
> knowledge, currently next to impossible (and slow since you'd 
> have to parse and isolate code in .d file multiple times in a 
> separate process, then compile again to put it all together).
>
> So, to quote Walter, what compelling features would it bring? 
> Here's an example of a simple AOP program from the AOP wiki 
> page (probably not the best implementation, but the concept is 
> there):
>
>   struct BankType
>   {
>     void transfer() { ... }
>     void getMoneyBack() { ... }
>   }
>
>   struct Logger
>   {
>     void transfer() {
>       log("transferring money...");
>     }
>     void getMoneyBack() {
>       log("User requested money back");
>     }
>   }
>
> and now some magic...
>
>   string bankCode(T...)(T aspects) {
>     auto code = "struct Bank {";
>     auto members = [__traits(allMembers, Bank)];
>     foreach (m; members) {
>       code ~= "void "~m~"() {";
>       code ~= __traits(getMember, Bank, m).codeof;
>       foreach (a; aspects) {
>         if (__traits(hasMember, a, m) {
>           code ~= __traits(getMember, a, m).codeof;
>         }
>       }
>       code ~= "}"
>     }
>     return code ~ "}";
>   }
>
>   mixin template Bank(T...)
>   {
>     mixin(bankCode(T));
>   }
>
>   mixin Bank!Logger;
>
>   void main() {
>     auto b = Bank();
>     b.transfer(); // logs
>     b.getMoneyBack(); // ditto
>   }
>
> So this would allow us to make "Compilers" within the Compiler 
> (Codeception), since we could parse/strip/append any existing 
> code fragments together in endless combination. Generic 
> "Builders" could probably be built and put into a std.builder 
> lib for general use.
>
> One particular use I have in mind is for Behavior Objects (Game 
> Scripts). Each behavior would hold Property(T) objects which 
> define per-property, per-state "binding" dependencies (eg. 
> position.x.bind(other.x, State.Idle)) and execution code. On 
> release, the Property(T) object would be stripped away (leaving 
> just T) and it's behavior code "compressed" with others into 
> optimized functions.
>
> I don't know much about the internals of DMD, so I'm not sure 
> this is a realistic request, but I think the idea is 
> compelling. Also, for Attributes I'm not sure this technique is 
> really applicable. But it's possible that the compiler could 
> exploit this internally for certain Attributes like @GC.whatever




More information about the Digitalmars-d mailing list