www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - The Final(ize) Challenge

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
May 18 2009
next sibling parent reply Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
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 ide=

 existed, we're ready to start some serious butt-kick reflection facilitie=

 For starters, I'd like to present you with the following challenge. Given
 any class C, e.g.:

 class C
 {
 =A0 =A0void foo(int) { ... }
 =A0 =A0int 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
 {
 =A0 =A0final void foo(int a) { return super.foo(a); }
 =A0 =A0final 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.

There are two challenging aspects that I'm running into. The first is a more general statement about trying to generate functions with D's metaprogramming. It is a huge pain in the ass to actually create a function with a given name, because the only way that I know this can be done is with a string mixin. As soon as we venture into that territory, we have to consider things like how to convert a parameter type tuple into a string, and whether or not the .stringof a type will be correctly qualified (I've run into problems with this before, where some code in a library is not able to mix in a string because it doesn't import the same modules that the calling code does, and then you just get undefined identifier errors). For the love of all that is holy, can we PLEASE get something like __ident("blah")? This would be so much easier and would probably drastically reduce my use of string mixins in general. The second is worse. __ctor (if it exists) is not virtual, so it's not possible to get a list of overloads of it with __traits. One of two things has to change: either __traits needs a way to get overloads of nonvirtual functions (that seems like an incredible oversight!), or as Sean and others have proposed numerous times, derived classes should inherit ctors. This would eliminate the need to write forwarding constructors in the Finalize class altogether.
May 18 2009
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Jarrett Billingsley wrote:
 The second is worse.  __ctor (if it exists) is not virtual, so it's
 not possible to get a list of overloads of it with __traits.

This is a simple one: final class Finalize(C) : C { this(A...)(A args) if (is(new C(args)) { super(args); } } Andrei
May 18 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Jarrett Billingsley wrote:
 On Mon, May 18, 2009 at 1:48 PM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 Jarrett Billingsley wrote:
 The second is worse.  __ctor (if it exists) is not virtual, so it's
 not possible to get a list of overloads of it with __traits.

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

What the!

I know, I didn't close a paren :o). Andrei
May 18 2009
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Andrei Alexandrescu wrote:
 Jarrett Billingsley wrote:
 On Mon, May 18, 2009 at 1:48 PM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 Jarrett Billingsley wrote:
 The second is worse.  __ctor (if it exists) is not virtual, so it's
 not possible to get a list of overloads of it with __traits.

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

What the!

I know, I didn't close a paren :o). Andrei

And I forgot the typeof again :o(. Redux: final class Finalize(C) : C { this(A...)(A args) if (is(typeof(new C(args)))) { super(args); } } This won't compile with 2.030 (args is not visible in the if-clause), but it should, and Walter has fixed that in his tree already. Andrei
May 18 2009
prev sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Jarrett Billingsley wrote:
 On Mon, May 18, 2009 at 1:57 PM, Jarrett Billingsley
 <jarrett.billingsley gmail.com> wrote:
 On Mon, May 18, 2009 at 1:56 PM, Bill Baxter <wbaxter gmail.com> wrote:
 When did templated constructors start being allowed?!  I see nothing
 about it in the change log.


It doesn't work. Let me guess: 2.031. :P

It's hardly fair to issue a challenge which can only be completed [1] with an unreleased compiler only you have seen. Actually, that *still* isn't going to cut it: it won't handle ref or out arguments correctly. I'm not sure what it'd do with scope. We *really* need to come up with a sane solution to generalising on storage class. Every time I have to generate functions, they make my life a complete pain in the arse. The only solution I've found is this hideous hack that parses ParameterTuple!(T).stringof and builds an array of enums... yech. ... and yeah, when were you gonna tell us about templated ctors?! -- Daniel [1] Qualification because I know if I don't, I'll regret it: I'm assuming the next compiler does support templated ctors (as otherwise your "it's easy" statement is bogus) and that this is the only way of solving the problem (I can't think of any other way of doing it.)
May 19 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Daniel Keep wrote:
 
 Jarrett Billingsley wrote:
 On Mon, May 18, 2009 at 1:57 PM, Jarrett Billingsley
 <jarrett.billingsley gmail.com> wrote:
 On Mon, May 18, 2009 at 1:56 PM, Bill Baxter <wbaxter gmail.com> wrote:
 When did templated constructors start being allowed?!  I see nothing
 about it in the change log.



It's hardly fair to issue a challenge which can only be completed [1] with an unreleased compiler only you have seen.

I don't have 2.031 and I don't know whether it will fix the template constructor bug.
 Actually, that *still* isn't going to cut it: it won't handle ref or out
 arguments correctly.  I'm not sure what it'd do with scope.
 
 We *really* need to come up with a sane solution to generalising on
 storage class.  Every time I have to generate functions, they make my
 life a complete pain in the arse.  The only solution I've found is this
 hideous hack that parses ParameterTuple!(T).stringof and builds an array
 of enums... yech.

It's much easier to parse ParameterTuple!(T)[n].stringof. If it starts with "ref "/"out " then it's a ref/out.
 ... and yeah, when were you gonna tell us about templated ctors?!
 
   -- Daniel
 
 
 [1] Qualification because I know if I don't, I'll regret it: I'm
 assuming the next compiler does support templated ctors (as otherwise
 your "it's easy" statement is bogus) and that this is the only way of
 solving the problem (I can't think of any other way of doing it.)

You could for now comment out the constructor and leave it until the bug is fixed. Andrei
May 19 2009
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Andrei Alexandrescu wrote:
 Daniel Keep wrote:
 ...

 It's hardly fair to issue a challenge which can only be completed [1]
 with an unreleased compiler only you have seen.

I don't have 2.031 and I don't know whether it will fix the template constructor bug.

Dude, you got my hopes up with that. :'(
 Actually, that *still* isn't going to cut it: it won't handle ref or out
 arguments correctly.  I'm not sure what it'd do with scope.

 We *really* need to come up with a sane solution to generalising on
 storage class.  Every time I have to generate functions, they make my
 life a complete pain in the arse.  The only solution I've found is this
 hideous hack that parses ParameterTuple!(T).stringof and builds an array
 of enums... yech.

It's much easier to parse ParameterTuple!(T)[n].stringof. If it starts with "ref "/"out " then it's a ref/out.

These magic tuples have a horrible habit of losing this invisible extra information when you so much as think about them. I didn't realise you could safely index them. What bothers me more is that as far as I can work out, ParameterTuple!(T) shouldn't exist in D in its current form. Its elements aren't types since when you use .stringof on them, they know their own storage class. And I'm pretty sure you can't pass the tuple around without it losing the storage classes (I gave up trying to figure out exactly under which circumstances this happened and just passed the function type's stringof around.) Maybe the underlying is() expression could be changed to return something like (StorageDefault, int, StorageRef, int, StorageOut, out) instead (given that the Storage* types are defined in object.d as typedefs of void or something.) Or maybe have a new trait or is() form that tells us the storage classes as with a tuple of strings. Then we wouldn't need to rely on a spec-defying feature. -- Daniel
May 19 2009
parent Georg Wrede <georg.wrede iki.fi> writes:
Daniel Keep wrote:
 
 These magic tuples have a horrible habit of losing this invisible extra
 information when you so much as think about them.  I didn't realise you
 could safely index them.
 
 What bothers me more is that as far as I can work out,
 ParameterTuple!(T) shouldn't exist in D in its current form.  Its
 elements aren't types since when you use .stringof on them, they know
 their own storage class.  And I'm pretty sure you can't pass the tuple
 around without it losing the storage classes (I gave up trying to figure
 out exactly under which circumstances this happened and just passed the
 function type's stringof around.)

This should be _much_ easier. Currently, it's way too complicated for all but the most persistent ones of us.
May 19 2009
prev sibling next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Jarrett Billingsley wrote:
 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.

There are two challenging aspects that I'm running into. The first is a more general statement about trying to generate functions with D's metaprogramming. It is a huge pain in the ass to actually create a function with a given name, because the only way that I know this can be done is with a string mixin. As soon as we venture into that territory, we have to consider things like how to convert a parameter type tuple into a string, and whether or not the .stringof a type will be correctly qualified (I've run into problems with this before, where some code in a library is not able to mix in a string because it doesn't import the same modules that the calling code does, and then you just get undefined identifier errors). For the love of all that is holy, can we PLEASE get something like __ident("blah")? This would be so much easier and would probably drastically reduce my use of string mixins in general.

Better __traits(ident, "blah")?
May 18 2009
parent Daniel Keep <daniel.keep.lists gmail.com> writes:
Ary Borenszweig wrote:
 Jarrett Billingsley wrote:
 ...  For
 the love of all that is holy, can we PLEASE get something like
 __ident("blah")?  This would be so much easier and would probably
 drastically reduce my use of string mixins in general.

Better __traits(ident, "blah")?

That'd only make sense if it was interrogative; it's constructive. -- Daniel
May 19 2009
prev sibling parent Christopher Wright <dhasenan gmail.com> writes:
Jarrett Billingsley wrote:
 The second is worse.  __ctor (if it exists) is not virtual, so it's
 not possible to get a list of overloads of it with __traits.  One of
 two things has to change: either __traits needs a way to get overloads
 of nonvirtual functions (that seems like an incredible oversight!), or
 as Sean and others have proposed numerous times, derived classes
 should inherit ctors.  This would eliminate the need to write
 forwarding constructors in the Finalize class altogether.

http://d.puremagic.com/issues/show_bug.cgi?id=2855
May 18 2009
prev sibling next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Mon, May 18, 2009 at 1:48 PM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
 Jarrett Billingsley wrote:
 The second is worse. =A0__ctor (if it exists) is not virtual, so it's
 not possible to get a list of overloads of it with __traits.

This is a simple one: final class Finalize(C) : C { =A0 =A0this(A...)(A args) if (is(new C(args)) =A0 =A0{ =A0 =A0 =A0 =A0super(args); =A0 =A0} }

What the!
May 18 2009
prev sibling next sibling parent reply Christian Kamm <kamm-incasoftware removethis.de> writes:
Andrei Alexandrescu 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.

Unless there's been a change in D2 I have missed, I don't think you can forward functions with ref/out or default arguments correctly unless you parse certain mangles or stringofs.
May 18 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Christian Kamm wrote:
 Andrei Alexandrescu 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.

Unless there's been a change in D2 I have missed, I don't think you can forward functions with ref/out or default arguments correctly unless you parse certain mangles or stringofs.

Time for a bug report. Andrei
May 18 2009
parent reply Christian Kamm <kamm-incasoftware removethis.de> writes:
 Unless there's been a change in D2 I have missed, I don't think you can
 forward functions with ref/out or default arguments correctly unless you
 parse certain mangles or stringofs.
 
 

Time for a bug report. Andrei

See http://d.puremagic.com/issues/show_bug.cgi?id=1818 or the related http://d.puremagic.com/issues/show_bug.cgi?id=1411 http://d.puremagic.com/issues/show_bug.cgi?id=1424 Treating default arguments or storage classes with the current scheme is difficult though - they are not part of the type. While the concept of an 'function argument description' including type, storage class, default argument and identifier (!) exists in the frontend, it is not exposed to the user - except through tuples in a fairly accidental and inconsistent manner.
May 18 2009
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Christian Kamm wrote:
 Unless there's been a change in D2 I have missed, I don't think you can
 forward functions with ref/out or default arguments correctly unless you
 parse certain mangles or stringofs.

Andrei

See http://d.puremagic.com/issues/show_bug.cgi?id=1818 or the related http://d.puremagic.com/issues/show_bug.cgi?id=1411 http://d.puremagic.com/issues/show_bug.cgi?id=1424 Treating default arguments or storage classes with the current scheme is difficult though - they are not part of the type. While the concept of an 'function argument description' including type, storage class, default argument and identifier (!) exists in the frontend, it is not exposed to the user - except through tuples in a fairly accidental and inconsistent manner.

Yes. All we need is a module std.reflection that does all that gruntwork and exposes a simple and nice interface for people who want to use reflection. Andrei
May 18 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Mon, May 18, 2009 at 10:53 AM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
 Jarrett Billingsley wrote:
 On Mon, May 18, 2009 at 1:48 PM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 Jarrett Billingsley wrote:
 The second is worse. =A0__ctor (if it exists) is not virtual, so it's
 not possible to get a list of overloads of it with __traits.

This is a simple one: final class Finalize(C) : C { =A0 this(A...)(A args) if (is(new C(args)) =A0 { =A0 =A0 =A0 super(args); =A0 } }

What the!

I know, I didn't close a paren :o).

When did templated constructors start being allowed?! I see nothing about it in the change log. --bb
May 18 2009
prev sibling next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Mon, May 18, 2009 at 1:56 PM, Bill Baxter <wbaxter gmail.com> wrote:
 When did templated constructors start being allowed?! =A0I see nothing
 about it in the change log.

I was about to say the same thing.
May 18 2009
prev sibling next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Mon, May 18, 2009 at 1:57 PM, Jarrett Billingsley
<jarrett.billingsley gmail.com> wrote:
 On Mon, May 18, 2009 at 1:56 PM, Bill Baxter <wbaxter gmail.com> wrote:
 When did templated constructors start being allowed?! =A0I see nothing
 about it in the change log.

I was about to say the same thing.

It doesn't work. Let me guess: 2.031. :P
May 18 2009
prev sibling next sibling parent reply Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Mon, May 18, 2009 at 1:23 PM, Jarrett Billingsley
<jarrett.billingsley gmail.com> wrote:

 The first is a more general statement about trying to generate
 functions with D's metaprogramming. =A0It is a huge pain in the ass to
 actually create a function with a given name, because the only way
 that I know this can be done is with a string mixin. =A0As soon as we
 venture into that territory, we have to consider things like how to
 convert a parameter type tuple into a string, and whether or not the
 .stringof a type will be correctly qualified (I've run into problems
 with this before, where some code in a library is not able to mix in a
 string because it doesn't import the same modules that the calling
 code does, and then you just get undefined identifier errors). =A0For
 the love of all that is holy, can we PLEASE get something like
 __ident("blah")? =A0This would be so much easier and would probably
 drastically reduce my use of string mixins in general.

What about this front? Is it out of the realm of possibility to get an identifier-izer?
May 18 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Jarrett Billingsley wrote:
 On Mon, May 18, 2009 at 1:23 PM, Jarrett Billingsley
 <jarrett.billingsley gmail.com> wrote:
 
 The first is a more general statement about trying to generate
 functions with D's metaprogramming.  It is a huge pain in the ass to
 actually create a function with a given name, because the only way
 that I know this can be done is with a string mixin.  As soon as we
 venture into that territory, we have to consider things like how to
 convert a parameter type tuple into a string, and whether or not the
 .stringof a type will be correctly qualified (I've run into problems
 with this before, where some code in a library is not able to mix in a
 string because it doesn't import the same modules that the calling
 code does, and then you just get undefined identifier errors).  For
 the love of all that is holy, can we PLEASE get something like
 __ident("blah")?  This would be so much easier and would probably
 drastically reduce my use of string mixins in general.

What about this front? Is it out of the realm of possibility to get an identifier-izer?

I want this too, but first let's become able to do things we can't do and then to do things we can do, easier. The __ident thing has been on the table for literally years, I seem to recall I called it new alias("blah"). Andrei
May 18 2009
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Jarrett Billingsley wrote:
 On Mon, May 18, 2009 at 2:20 PM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 I want this too, but first let's become able to do things we can't do and
 then to do things we can do, easier. The __ident thing has been on the table
 for literally years, I seem to recall I called it new alias("blah").

I'm more worried that this will just slip through the cracks and not make it into D2. Then it'd be implemented in some post-D2 version of DMD, and then D3 will be forked, so it'll _kind of_ be part of D2 but not _really_ since it wasn't part of the spec when it was 'frozen'.. we've been here before :P It seems like such low-hanging fruit. So many of my string mixins only exist to parameterize the names of things that this would almost completely replace them. It's on the same level as static foreach - not essential, but it'd certainly make a lot of metaprogramming simpler.

I think you need to operate exclusively with string mixins in Finalize, so __ident would be of marginal help there. Also, static foreach is much more necessary. Andrei
May 18 2009
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Jarrett Billingsley wrote:
 On Mon, May 18, 2009 at 2:34 PM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 
 I think you need to operate exclusively with string mixins in Finalize, so
 __ident would be of marginal help there. Also, static foreach is much more
 necessary.

I have used string mixins extensively in my own code, not just in this one example.

Then implement Finalize. Too much foreplay. Andrei
May 18 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Jarrett Billingsley wrote:
 On Mon, May 18, 2009 at 2:48 PM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 
 Then implement Finalize. Too much foreplay.

I thought it was already established that it's currently impossible. Ctors? Ref/out params? Hello?

I just showed you how to do ctors. I know how to do ref but why don't you do your due diligence. I don't think "out" is doable. Implement what you can and bugzillize what you can't. Andrei
May 18 2009
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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); } Andrei
May 18 2009
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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.

_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?

Submit a bug report asking for documentation. You'd be able to whine to an eskimo that there's too much snow on your sidewalk. Andrei
May 18 2009
prev sibling parent downs <default_357-line yahoo.de> writes:
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.

_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.
May 18 2009
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Jarrett Billingsley wrote:
 On Mon, May 18, 2009 at 2:55 PM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 
 I just showed you how to do ctors.

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.
 I know how to do ref but why don't you do
 your due diligence.

My "due dilligence"? I wasn't aware that I was under contract!

Your whining is contract-binding. Andrei
May 18 2009
prev sibling parent reply Christopher Wright <dhasenan gmail.com> writes:
Andrei Alexandrescu wrote:
 I think you need to operate exclusively with string mixins in Finalize, 
 so __ident would be of marginal help there. Also, static foreach is much 
 more necessary.

That is a huge problem. Let's say that the class you want to finalize, Target, has a method like this: void foo(SomeClass){} Let's say that SomeClass is private and in the same module as Target. You *may* be able to do this with templates. Probably. You *can never* do this with a string mixin. Let's say you have another method: void bar(SomeOtherClass!(int)){} SomeOtherClass!(int).stringof == "SomeOtherClass". That is also guaranteed fail. What you can do is: void foo(ParameterTupleOf!(__traits(getVirtualFunctions, Target, "foo")[0] u) { super.foo(u); } Here, the only string you need to mix in is for the identifier.
May 18 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Christopher Wright wrote:
 Andrei Alexandrescu wrote:
 I think you need to operate exclusively with string mixins in 
 Finalize, so __ident would be of marginal help there. Also, static 
 foreach is much more necessary.

That is a huge problem. Let's say that the class you want to finalize, Target, has a method like this: void foo(SomeClass){} Let's say that SomeClass is private and in the same module as Target. You *may* be able to do this with templates. Probably. You *can never* do this with a string mixin.

Of course you can. All you have to do is first check whether the call is accessible from your instantiation point, BEFORE generating the string. Andrei
May 18 2009
parent Christopher Wright <dhasenan gmail.com> writes:
Andrei Alexandrescu wrote:
 Christopher Wright wrote:
 Andrei Alexandrescu wrote:
 I think you need to operate exclusively with string mixins in 
 Finalize, so __ident would be of marginal help there. Also, static 
 foreach is much more necessary.

That is a huge problem. Let's say that the class you want to finalize, Target, has a method like this: void foo(SomeClass){} Let's say that SomeClass is private and in the same module as Target. You *may* be able to do this with templates. Probably. You *can never* do this with a string mixin.

Of course you can. All you have to do is first check whether the call is accessible from your instantiation point, BEFORE generating the string. Andrei

And a lot of interesting usages will have the Finalize template instantiated far from user code, but then passed back to user code. This means you can't do much at all with string mixins. I faced that problem with dmocks and didn't find a good solution for it while still working on dmocks.
May 18 2009
prev sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
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. =A0Which 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=3D2782
May 18 2009
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 18 May 2009 12: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!

1 minor issue, if super.foo(a) calls bar, then it's still a virtual call... Not that it's not a good idea, but you might get a lot less mileage out of it than you think. I think you'd need compiler help to get rid of that problem. It'd be like a flattening of a class to recompile all base class virtual calls with the notion that any internal calls it makes are final. If you casted to a base class, the initial call would be virtual, but the internal calls would be nonvirtual. This would be impossible unless you had the source to all the base classes, it might just be better to do it as a separate code-generator tool. Back to your idea... This feature that you suggest seems very trivial for the compiler to implement, while extremely hard to do it via reflection. I've longed for this for a while: interface I { int foo(); } class A { int foo() {return 0;} } class B: A, I { alias A.foo foo; } which makes B implement the interface by simply copying the vtable entry from A's. This even saves on the double call (having a derived class function that simply calls the base class function). You could then allow: class B: A, I { final alias A.foo foo; } and the compiler knows it doesn't need a virtual lookup. Then the template to do it to all virtual methods would be trivial. -Steve
May 18 2009
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Steven Schveighoffer wrote:
 Back to your idea...
 
 This feature that you suggest seems very trivial for the compiler to 
 implement, while extremely hard to do it via reflection.

The problem is, there are a million things that are trivial for the compiler to implement and harder with libraries. But that approach just doesn't scale. Finalize is only the beginning and pretty much a working example to flesh out library primitives. Don't get bogged down by it. Andrei
May 18 2009
prev sibling next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Mon, May 18, 2009 at 2:20 PM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
 I want this too, but first let's become able to do things we can't do and
 then to do things we can do, easier. The __ident thing has been on the table
 for literally years, I seem to recall I called it new alias("blah").

I'm more worried that this will just slip through the cracks and not make it into D2. Then it'd be implemented in some post-D2 version of DMD, and then D3 will be forked, so it'll _kind of_ be part of D2 but not _really_ since it wasn't part of the spec when it was 'frozen'.. we've been here before :P It seems like such low-hanging fruit. So many of my string mixins only exist to parameterize the names of things that this would almost completely replace them. It's on the same level as static foreach - not essential, but it'd certainly make a lot of metaprogramming simpler.
May 18 2009
prev sibling next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Mon, May 18, 2009 at 2:34 PM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:

 I think you need to operate exclusively with string mixins in Finalize, so
 __ident would be of marginal help there. Also, static foreach is much more
 necessary.

I have used string mixins extensively in my own code, not just in this one example. Most of the time it's to replace a name. With something like __ident, I wouldn't have to use them nearly as much, and in fact I probably wouldn't need them here. Think about it: template CreateOverload(alias func, char[] name) { ReturnType!(func) __ident(name)(ParameterTypeTuple!(func) args) { return super.__ident(name)(args); } } Then later, I could just use a template mixin. You say static foreach is much more necessary than this. Why? It's just a convenience, so you don't have to use template recursion. Is it more important because you want to use it?
May 18 2009
prev sibling next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Mon, May 18, 2009 at 2:48 PM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:

 Then implement Finalize. Too much foreplay.

I thought it was already established that it's currently impossible. Ctors? Ref/out params? Hello?
May 18 2009
prev sibling next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Mon, May 18, 2009 at 2:55 PM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:

 I just showed you how to do ctors.

No, you showed me how ctors would be done if I had a correctly-functioning compiler. Which I don't.
 I know how to do ref but why don't you do
 your due diligence.

My "due dilligence"? I wasn't aware that I was under contract!
May 18 2009
prev sibling next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
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 =

 _param_0)":

 struct S
 {
 =A0 =A0void blah(out int) {}
 }

 void main()
 {
 =A0 =A0writeln(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?
May 18 2009
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 18 May 2009 14:37:51 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Steven Schveighoffer wrote:
 Back to your idea...
  This feature that you suggest seems very trivial for the compiler to  
 implement, while extremely hard to do it via reflection.

The problem is, there are a million things that are trivial for the compiler to implement and harder with libraries. But that approach just doesn't scale. Finalize is only the beginning and pretty much a working example to flesh out library primitives. Don't get bogged down by it.

Sure, there's a library solution. But what I'm saying is, it coincides with a different problem, where both can be solved by adding some intuitive syntax. Without adding the cruft of a dispatch function, D can provide an intuitive way to specify the layout of the vtable. And that would make your problem easier to solve. Not only that, the performance of simply copying the function in the vtable is impossible to achieve through a library solution. -Steve
May 18 2009
prev sibling next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
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
prev sibling next sibling parent reply "Denis Koroskin" <2korden gmail.com> writes:
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
next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Mon, May 18, 2009 at 5:02 PM, Denis Koroskin <2korden gmail.com> wrote:
 template Finalize(T)
 {
 =A0 final class Finalize : T
 =A0 {
 =A0 =A0 =A0 this(Args...)(Args args)
 =A0 =A0 =A0 {
 =A0 =A0 =A0 =A0 =A0 super(args);
 =A0 =A0 =A0 }
 =A0 }
 }

 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
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
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
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Frits van Bommel wrote:
 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; }

Damn. I meant to NOT inherit from A. Andrei
May 18 2009
prev sibling next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
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 ide=

 existed, we're ready to start some serious butt-kick reflection facilitie=

 For starters, I'd like to present you with the following challenge. Given
 any class C, e.g.:

 class C
 {
 =A0 =A0void foo(int) { ... }
 =A0 =A0int 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
 {
 =A0 =A0final void foo(int a) { return super.foo(a); }
 =A0 =A0final 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 =3D func.stringof; int begin =3D s.length - 1; int nesting =3D 0; for(; begin > 0; begin--) { if(s[begin] =3D=3D ')') nesting++; else if(s[begin] =3D=3D '(') { nesting--; if(nesting =3D=3D 0) break; } } return s[begin .. $]; } string ParamList(func)() { auto s =3D ParamTypes!(func)()[1 .. $ - 1]; // strip off parens string ret =3D " "; // 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 =3D 0; foreach(i, c; s) { if(c =3D=3D ' ') lastSpace =3D i; else if(c =3D=3D ',') ret ~=3D s[lastSpace + 1 .. i] ~ ","; } if(s.length - lastSpace > 0) ret ~=3D s[lastSpace + 1 .. $] ~ ","; return ret[0 .. $ - 1]; // chop off trailing comma } template VirtualOverloadImpl(string methodName, alias method) { enum VirtualOverloadImpl =3D "override " ~ ReturnType!(method).stringof ~ " " ~ methodName ~ ParamTypes!(typeof(&method))() ~ "{ return super." ~ methodName ~ "(" ~ ParamList!(typeof(&method))() ~ ");= }"; } string VirtualOverloads(T, string method)() { string ret =3D ""; foreach(overload; __traits(getVirtualFunctions, T, method)) { ret ~=3D "override " ~ ReturnType!(overload).stringof ~ " " ~ method ~ ParamTypes!(typeof(&overload))() ~ "{ return super." ~ method ~ "(" ~ ParamList!(typeof(&overload))() ~ "); = }\n"; } return ret; } template FinalizeMembers(T, size_t idx =3D 0) { static if(idx >=3D __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 =3D new C(); c.foo(4.9); writeln(c.bar("5")); auto c2 =3D 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
prev sibling next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
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
prev sibling next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
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
prev sibling next sibling parent reply Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Mon, May 18, 2009 at 12:12 PM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:

 Have at it!

Well? Where's my cookie? ;)
May 18 2009
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Jarrett Billingsley wrote:
 On Mon, May 18, 2009 at 12:12 PM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 
 Have at it!

Well? Where's my cookie? ;)

As soon as I'm coming off my prostration and awe engendered by your solution, I'll reply to that. I have to admit, though, that Denis' insight sort of took the wind out of my sails. Thanks! Andrei
May 18 2009
prev sibling next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Mon, May 18, 2009 at 6:54 PM, Christopher Wright <dhasenan gmail.com> wrote:
 Andrei Alexandrescu wrote:
 I think you need to operate exclusively with string mixins in Finalize, so
 __ident would be of marginal help there. Also, static foreach is much more
 necessary.

That is a huge problem. Let's say that the class you want to finalize, Target, has a method like this: void foo(SomeClass){} Let's say that SomeClass is private and in the same module as Target. You *may* be able to do this with templates. Probably. You *can never* do this with a string mixin.

Exactly. This is one of the problems I mentioned earlier, and I know Andrei's got experience with this as well - std.algorithm doesn't import std.math by default, so you can't use math functions in the string expressions. Oh sure, you could kludge that in there, but it's far from scalable.
May 18 2009
prev sibling next sibling parent davidl <davidl nospam.org> writes:
在 Tue, 19 May 2009 05:29:09 +0800,Jarrett Billingsley  
<jarrett.billingsley gmail.com> 写道:

 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); } }

Err this sort of __ident is implemented by my patch against allMembers. It's arranged as: [ "membername", membersymbol, "member2name", membersymbol] that is __traits(allMembers, ClassSym)[1](3,4) would call the second member of ClassSym with args (3,4) -- 使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/
May 19 2009
prev sibling parent reply "Guillaume B." <guillaume.b.spam spam.ca> writes:
Andrei Alexandrescu wrote:
 
 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.
 

Hi, I don't fully understand the uses of Finalize!(C)... But for logging (or timing), this kind of template could be useful... it think!... Anyway, something like this: class MagicLog(T) : T { // D Magic... } Could turn a class like this: class C { int foo() { ... } } to this: class MagicLogC { int foo() { Log.write("Entering foo()"); scope(success) Log.write("Leaving foo(): success"); scope(failure) Log.write("Leaving foo(): failure"); return super.foo(); } } And then, somewhere else: version(WithMagicLog) { C c = new MagicLog!(C); // With logging } else { C c = new C; // Full speed, no logging } int i = c.foo(); Seems pretty useful to me! :) The only problem is writing the MagicLog class. Guillaume B.
May 22 2009
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Guillaume B. wrote:
 Andrei Alexandrescu wrote:
 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.

Hi, I don't fully understand the uses of Finalize!(C)... But for logging (or timing), this kind of template could be useful... it think!... Anyway, something like this: class MagicLog(T) : T { // D Magic... } Could turn a class like this: class C { int foo() { ... } } to this: class MagicLogC { int foo() { Log.write("Entering foo()"); scope(success) Log.write("Leaving foo(): success"); scope(failure) Log.write("Leaving foo(): failure"); return super.foo(); } } And then, somewhere else: version(WithMagicLog) { C c = new MagicLog!(C); // With logging } else { C c = new C; // Full speed, no logging } int i = c.foo(); Seems pretty useful to me! :) The only problem is writing the MagicLog class.

"A simple matter of programming." It's a great idea, and a means to tap into AOP-style programming by using reflection. Andrei
May 22 2009