May 18, 2009
On Mon, May 18, 2009 at 3:11 PM, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

>> No, you showed me how ctors would be done if I had a correctly-functioning compiler.  Which I don't.
>
> I'm not seeing the bugzilla you submitted.

Oh look at that, someone's already reported it.

http://d.puremagic.com/issues/show_bug.cgi?id=2782
May 18, 2009
On Mon, May 18, 2009 at 3:14 PM, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
>
> Submit a bug report asking for documentation.

http://d.puremagic.com/issues/show_bug.cgi?id=3007

> You'd be able to whine to an
> eskimo that there's too much snow on your sidewalk.

The squeaky wheel gets the grease.
May 18, 2009
On Mon, 18 May 2009 20:12:40 +0400, Andrei Alexandrescu <SeeWebsiteForEmail@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!
>
> Andrei

template Finalize(T)
{
   final class Finalize : T
   {
       this(Args...)(Args args)
       {
           super(args);
       }
   }
}

The following code /should/ work as you ask. There is no need to iterate over all the methods and make a final version out of it for two reasons
1) It is redundant
2) It creates an additional overhead

unless that's was you *really* need.

Future work: Finalize!(T) should resolve to T iff T is already final.


May 18, 2009
On Mon, May 18, 2009 at 5:02 PM, Denis Koroskin <2korden@gmail.com> wrote:
>
> template Finalize(T)
> {
>   final class Finalize : T
>   {
>       this(Args...)(Args args)
>       {
>           super(args);
>       }
>   }
> }
>
> The following code /should/ work as you ask. There is no need to iterate
> over all the methods and make a final version out of it for two reasons
> 1) It is redundant
> 2) It creates an additional overhead

If you ask __traits(isFinalFunction, Finalize!(C).something), you
always get false.
May 18, 2009
Denis Koroskin wrote:
> On Mon, 18 May 2009 20:12:40 +0400, Andrei Alexandrescu <SeeWebsiteForEmail@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!
>>
>> Andrei
> 
> template Finalize(T)
> {
>    final class Finalize : T
>    {
>        this(Args...)(Args args)
>        {
>            super(args);
>        }
>    }
> }
> 
> The following code /should/ work as you ask. There is no need to iterate over all the methods and make a final version out of it for two reasons
> 1) It is redundant
> 2) It creates an additional overhead
> 
> unless that's was you *really* need.
> 
> Future work: Finalize!(T) should resolve to T iff T is already final.

Good point! Now define Unfinalize that opens the final methods of a class for method overriding.

class A
{
    final int foo(string) { ... }
}

class UnfinalizeA : A
{
    int foo(string a) { return super.foo(a); }
}


Andrei
May 18, 2009
On Mon, May 18, 2009 at 12:12 PM, Andrei Alexandrescu <SeeWebsiteForEmail@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.
May 18, 2009
On Mon, May 18, 2009 at 5:12 PM, Jarrett Billingsley <jarrett.billingsley@gmail.com> wrote:

> 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.

I should also mention another issue I ran into when writing this. Template alias params do not seem to distinguish between multiple overloads of the same symbol, which kind of makes sense, but which made the ParamTypes and ParamList functions work incorrectly when I wrote them initially.  That is, the compiler would reuse the template instantiation of the first overload I passed to it for all subsequent overloads.  I think this may be in bugzilla already.
May 18, 2009
On Mon, May 18, 2009 at 5:12 PM, Jarrett Billingsley <jarrett.billingsley@gmail.com> wrote:
> ...

Aaand for contrast, if we had __ident and static foreach:

final class Finalize(T) : T
{
	this(T...)(T args) if(is(typeof(new T(args)))) { super(args); }

	static foreach(member; __traits(allMembers, T))
		static if(__traits(isVirtualFunction, __traits(getMember, T,
member)) && !__traits(isFinalFunction, __traits(getMember, T,
member)))
			override ReturnType!(__traits(getMember, T, member))
__ident(member)(ParameterTypeTuple!(__traits(getMember, T, member)
args)
				{ return super.__ident(member)(args); }
}
May 18, 2009
Andrei Alexandrescu wrote:
> Good point! Now define Unfinalize that opens the final methods of a class for method overriding.
> 
> class A
> {
>     final int foo(string) { ... }
> }
> 
> class UnfinalizeA : A
> {
>     int foo(string a) { return super.foo(a); }
> }

DMD rightly doesn't allow this:
---
test.d(8): Error: function test.UnfinalizeA.foo cannot override final function test.A.foo
---

There's a workaround though:
---
class UnfinalizeA : A
{
    int foo_(string a) { return super.foo(a); }
    alias foo_ foo;
}
---
May 18, 2009
Jarrett Billingsley wrote:
> On Mon, May 18, 2009 at 2:57 PM, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
>> Andrei Alexandrescu wrote:
>>> I don't think "out" is doable.
>> I take that back. It is doable. The code below prints "void function(out int
>> _param_0)":
>>
>> struct S
>> {
>>    void blah(out int) {}
>> }
>>
>> void main()
>> {
>>    writeln(typeof(&S.blah).stringof);
>> }
> 
> Wonderful, I can extract information about parameters through a completely undocumented mechanism.  What guarantee do I have that this will work with another frontend or version of DMD?

I have to second this one - parsing stringof "feels" wrong.

It's like taking a detour over a language only tangentially related to D.