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