Le 22/03/2012 17:00, F i L a écrit :
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
As of discussion about properties/attributes, I wanted to do a proposal
along that line :
@ttribute attributeName(AST ast, other template parameters . . .) {
// Eponymous trick
immutable AST attributeName = process(ast);
auto process(AST ast) {
// Do some CTFEable ast magic here.
return newAst;
}
}
And that would be used that way :
@attributeName(other template parameters if it make sense)
void fun() {}
And allow us to do inception within fun.
Additionally, I wanted to propose @mixin that return the AST of a string.
This isn't as easy as you think, it have a lot lot of implication about
what you get as string. This is definitively interesting, but require
more work for a realistic proposal.