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