The Final(ize) Challenge
Jarrett Billingsley
jarrett.billingsley at gmail.com
Mon May 18 14:12:30 PDT 2009
On Mon, May 18, 2009 at 12:12 PM, Andrei Alexandrescu
<SeeWebsiteForEmail at erdani.org> wrote:
> Ok, now with the advent (or rediscovery) of allMembers which I had no idea
> existed, we're ready to start some serious butt-kick reflection facilities.
>
> For starters, I'd like to present you with the following challenge. Given
> any class C, e.g.:
>
> class C
> {
> void foo(int) { ... }
> int bar(string) { ... }
> }
>
> define a template class Finalize(T) such that Finalize!(C) is the same as
> the following hand-written class:
>
> final class FinalizeC : C
> {
> final void foo(int a) { return super.foo(a); }
> final int bar(string a) { return super.bar(a); }
> }
>
> Finalize is cool when you need some functionality from an exact class and
> you don't want to pay indirect calls throughout. All calls through
> Finalize!(C)'s methods will resolve to static calls.
>
>
> Have at it!
module foo;
import std.conv;
import std.bind;
import std.stdio;
import std.traits;
import std.metastrings;
string ParamTypes(func)()
{
auto s = func.stringof;
int begin = s.length - 1;
int nesting = 0;
for(; begin > 0; begin--)
{
if(s[begin] == ')')
nesting++;
else if(s[begin] == '(')
{
nesting--;
if(nesting == 0)
break;
}
}
return s[begin .. $];
}
string ParamList(func)()
{
auto s = ParamTypes!(func)()[1 .. $ - 1]; // strip off parens
string ret = " ";
// could have weird spaces in the type, so look for a comma and get
the text from the last space until it
size_t lastSpace = 0;
foreach(i, c; s)
{
if(c == ' ')
lastSpace = i;
else if(c == ',')
ret ~= s[lastSpace + 1 .. i] ~ ",";
}
if(s.length - lastSpace > 0)
ret ~= s[lastSpace + 1 .. $] ~ ",";
return ret[0 .. $ - 1]; // chop off trailing comma
}
template VirtualOverloadImpl(string methodName, alias method)
{
enum VirtualOverloadImpl = "override " ~ ReturnType!(method).stringof
~ " " ~ methodName ~ ParamTypes!(typeof(&method))() ~
"{ return super." ~ methodName ~ "(" ~ ParamList!(typeof(&method))() ~ "); }";
}
string VirtualOverloads(T, string method)()
{
string ret = "";
foreach(overload; __traits(getVirtualFunctions, T, method))
{
ret ~= "override " ~ ReturnType!(overload).stringof ~ " " ~ method ~
ParamTypes!(typeof(&overload))() ~
"{ return super." ~ method ~ "(" ~ ParamList!(typeof(&overload))() ~ "); }\n";
}
return ret;
}
template FinalizeMembers(T, size_t idx = 0)
{
static if(idx >= __traits(allMembers, T).length)
alias void FinalizeMembers;
else
{
static if(__traits(isVirtualFunction, __traits(getMember, T,
__traits(allMembers, T)[idx])) &&
!__traits(isFinalFunction, __traits(getMember, T,
__traits(allMembers, T)[idx])))
{
mixin(VirtualOverloads!(T, __traits(allMembers, T)[idx])());
}
mixin FinalizeMembers!(T, idx + 1);
}
}
final class Finalize(T) : T
{
// this(T...)(T args) if(is(typeof(new T(args)))) { super(args); }
mixin FinalizeMembers!T;
}
class C
{
// this(int x) { writefln("new C: %s", x); }
void foo(float x) { writeln(x); }
void foo(char c) { writeln(c); }
int bar(string s) { return to!int(s); }
}
void main()
{
auto c = new C();
c.foo(4.9);
writeln(c.bar("5"));
auto c2 = new Finalize!(C)();
c2.foo(4.9);
writeln(c2.bar("5"));
}
Weird bug: if one of your methods takes a single int parameter (no
more, no less, and it has to be 'int', no other basic type triggers
it), DMD inserts a spurious pair of parens in the .stringof, as in
"void function((int))", causing the parameter type and name extraction
to fail.
More information about the Digitalmars-d
mailing list