digitalmars.D - The Final(ize) Challenge
- Andrei Alexandrescu (22/22) May 18 2009 Ok, now with the advent (or rediscovery) of allMembers which I had no
- Jarrett Billingsley (25/44) May 18 2009 a
- Andrei Alexandrescu (10/12) May 18 2009 This is a simple one:
- Jarrett Billingsley (3/15) May 18 2009 What the!
- Andrei Alexandrescu (3/19) May 18 2009 I know, I didn't close a paren :o).
- Andrei Alexandrescu (12/33) May 18 2009 And I forgot the typeof again :o(. Redux:
- Bill Baxter (5/27) May 18 2009 When did templated constructors start being allowed?! I see nothing
- Jarrett Billingsley (2/4) May 18 2009 I was about to say the same thing.
- Jarrett Billingsley (3/8) May 18 2009 It doesn't work. Let me guess: 2.031. :P
- Daniel Keep (16/25) May 19 2009 It's hardly fair to issue a challenge which can only be completed [1]
- Andrei Alexandrescu (8/38) May 19 2009 I don't have 2.031 and I don't know whether it will fix the template
- Daniel Keep (19/38) May 19 2009 These magic tuples have a horrible habit of losing this invisible extra
- Georg Wrede (3/15) May 19 2009 This should be _much_ easier. Currently, it's way too complicated for
- Ary Borenszweig (2/44) May 18 2009 Better __traits(ident, "blah")?
- Daniel Keep (3/10) May 19 2009 That'd only make sense if it was interrogative; it's constructive.
- Christopher Wright (2/9) May 18 2009 http://d.puremagic.com/issues/show_bug.cgi?id=2855
- Christian Kamm (4/9) May 18 2009 Unless there's been a change in D2 I have missed, I don't think you can
- Andrei Alexandrescu (3/16) May 18 2009 Time for a bug report.
- Christian Kamm (10/19) May 18 2009 See
- Andrei Alexandrescu (5/25) May 18 2009 Yes. All we need is a module std.reflection that does all that gruntwork...
- Jarrett Billingsley (4/17) May 18 2009 What about this front? Is it out of the realm of possibility to get
- Andrei Alexandrescu (6/25) May 18 2009 I want this too, but first let's become able to do things we can't do
- Jarrett Billingsley (12/15) May 18 2009 I'm more worried that this will just slip through the cracks and not
- Andrei Alexandrescu (5/22) May 18 2009 I think you need to operate exclusively with string mixins in Finalize,
- Jarrett Billingsley (17/20) May 18 2009 I have used string mixins extensively in my own code, not just in this
- Andrei Alexandrescu (3/12) May 18 2009 Then implement Finalize. Too much foreplay.
- Jarrett Billingsley (4/5) May 18 2009 I thought it was already established that it's currently impossible.
- Andrei Alexandrescu (5/12) May 18 2009 I just showed you how to do ctors. I know how to do ref but why don't
- Andrei Alexandrescu (12/13) May 18 2009 I take that back. It is doable. The code below prints "void function(out...
- Jarrett Billingsley (6/19) May 18 2009 int
- Andrei Alexandrescu (4/24) May 18 2009 Submit a bug report asking for documentation. You'd be able to whine to
- Jarrett Billingsley (4/7) May 18 2009 http://d.puremagic.com/issues/show_bug.cgi?id=3007
- downs (3/23) May 18 2009 I have to second this one - parsing stringof "feels" wrong.
- Jarrett Billingsley (5/8) May 18 2009 No, you showed me how ctors would be done if I had a
- Andrei Alexandrescu (4/15) May 18 2009 Your whining is contract-binding.
- Jarrett Billingsley (4/7) May 18 2009 Oh look at that, someone's already reported it.
- Christopher Wright (16/19) May 18 2009 That is a huge problem.
- Jarrett Billingsley (6/18) May 18 2009 Exactly. This is one of the problems I mentioned earlier, and I know
- Andrei Alexandrescu (4/20) May 18 2009 Of course you can. All you have to do is first check whether the call is...
- Christopher Wright (6/29) May 18 2009 And a lot of interesting usages will have the Finalize template
- Steven Schveighoffer (38/59) May 18 2009 1 minor issue, if super.foo(a) calls bar, then it's still a virtual call...
- Andrei Alexandrescu (6/10) May 18 2009 The problem is, there are a million things that are trivial for the
- Steven Schveighoffer (11/19) May 18 2009 Sure, there's a library solution. But what I'm saying is, it coincides ...
- Denis Koroskin (16/38) May 18 2009 template Finalize(T)
- Jarrett Billingsley (3/17) May 18 2009 If you ask __traits(isFinalFunction, Finalize!(C).something), you
- Andrei Alexandrescu (12/65) May 18 2009 Good point! Now define Unfinalize that opens the final methods of a
- Frits van Bommel (14/26) May 18 2009 DMD rightly doesn't allow this:
- Andrei Alexandrescu (3/30) May 18 2009 Damn. I meant to NOT inherit from A.
- Jarrett Billingsley (107/127) May 18 2009 a
- Jarrett Billingsley (9/14) May 18 2009 I should also mention another issue I ran into when writing this.
- Jarrett Billingsley (15/16) May 18 2009 Aaand for contrast, if we had __ident and static foreach:
- davidl (10/26) May 19 2009 Err this sort of __ident is implemented by my patch against allMembers.
- Jarrett Billingsley (3/4) May 18 2009 Well? Where's my cookie? ;)
- Andrei Alexandrescu (6/12) May 18 2009 As soon as I'm coming off my prostration and awe engendered by your
- Guillaume B. (34/57) May 22 2009 Hi,
- Andrei Alexandrescu (5/70) May 22 2009 "A simple matter of programming."
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
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=aexisted, we're ready to start some serious butt-kick reflection facilitie=s.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
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
On Mon, May 18, 2009 at 1:48 PM, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Jarrett Billingsley wrote:What the!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} }
May 18 2009
Jarrett Billingsley wrote:On Mon, May 18, 2009 at 1:48 PM, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:I know, I didn't close a paren :o). AndreiJarrett Billingsley wrote:What the!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); } }
May 18 2009
Andrei Alexandrescu wrote:Jarrett Billingsley wrote: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. AndreiOn Mon, May 18, 2009 at 1:48 PM, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:I know, I didn't close a paren :o). AndreiJarrett Billingsley wrote:What the!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); } }
May 18 2009
On Mon, May 18, 2009 at 10:53 AM, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Jarrett Billingsley wrote:When did templated constructors start being allowed?! I see nothing about it in the change log. --bbOn Mon, May 18, 2009 at 1:48 PM, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:I know, I didn't close a paren :o).Jarrett Billingsley wrote:What the!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 } }
May 18 2009
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
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:It doesn't work. Let me guess: 2.031. :PWhen 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
Jarrett Billingsley wrote:On Mon, May 18, 2009 at 1:57 PM, Jarrett Billingsley <jarrett.billingsley gmail.com> wrote: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.)On Mon, May 18, 2009 at 1:56 PM, Bill Baxter <wbaxter gmail.com> wrote:It doesn't work. Let me guess: 2.031. :PWhen did templated constructors start being allowed?! I see nothing about it in the change log.I was about to say the same thing.
May 19 2009
Daniel Keep wrote:Jarrett Billingsley wrote:I don't have 2.031 and I don't know whether it will fix the template constructor bug.On Mon, May 18, 2009 at 1:57 PM, Jarrett Billingsley <jarrett.billingsley gmail.com> wrote:It's hardly fair to issue a challenge which can only be completed [1] with an unreleased compiler only you have seen.On Mon, May 18, 2009 at 1:56 PM, Bill Baxter <wbaxter gmail.com> wrote:It doesn't work. Let me guess: 2.031. :PWhen did templated constructors start being allowed?! I see nothing about it in the change log.I was about to say the same thing.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
Andrei Alexandrescu wrote:Daniel Keep wrote:Dude, you got my hopes up with that. :'(... 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.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. -- DanielActually, 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.
May 19 2009
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
Jarrett Billingsley wrote:On Mon, May 18, 2009 at 12:12 PM, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Better __traits(ident, "blah")?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.
May 18 2009
Ary Borenszweig wrote:Jarrett Billingsley wrote:That'd only make sense if it was interrogative; it's constructive. -- Daniel... 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 19 2009
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
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
Christian Kamm wrote:Andrei Alexandrescu wrote:Time for a bug report. AndreiOk, 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
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.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
Christian Kamm wrote: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. AndreiSee 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.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
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
Jarrett Billingsley wrote:On Mon, May 18, 2009 at 1:23 PM, Jarrett Billingsley <jarrett.billingsley gmail.com> 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"). AndreiThe 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?
May 18 2009
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
Jarrett Billingsley wrote:On Mon, May 18, 2009 at 2:20 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. AndreiI 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
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
Jarrett Billingsley wrote:On Mon, May 18, 2009 at 2:34 PM, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Then implement Finalize. Too much foreplay. AndreiI 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.
May 18 2009
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
Jarrett Billingsley wrote:On Mon, May 18, 2009 at 2:48 PM, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote: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. AndreiThen implement Finalize. Too much foreplay.I thought it was already established that it's currently impossible. Ctors? Ref/out params? Hello?
May 18 2009
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
On Mon, May 18, 2009 at 2:57 PM, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Andrei Alexandrescu wrote:intI 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
Jarrett Billingsley wrote:On Mon, May 18, 2009 at 2:57 PM, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote: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. AndreiAndrei Alexandrescu wrote: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 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); }
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=3007You'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
Jarrett Billingsley wrote:On Mon, May 18, 2009 at 2:57 PM, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:I have to second this one - parsing stringof "feels" wrong. It's like taking a detour over a language only tangentially related to D.Andrei Alexandrescu wrote: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 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); }
May 18 2009
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
Jarrett Billingsley wrote:On Mon, May 18, 2009 at 2:55 PM, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:I'm not seeing the bugzilla you submitted.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.Your whining is contract-binding. AndreiI 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
On Mon, May 18, 2009 at 3:11 PM, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Oh look at that, someone's already reported it. http://d.puremagic.com/issues/show_bug.cgi?id=3D2782No, 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.
May 18 2009
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
On Mon, May 18, 2009 at 6:54 PM, Christopher Wright <dhasenan gmail.com> wrote:Andrei Alexandrescu wrote: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.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.
May 18 2009
Christopher Wright wrote:Andrei Alexandrescu wrote: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. AndreiI 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.
May 18 2009
Andrei Alexandrescu wrote:Christopher Wright wrote: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.Andrei Alexandrescu wrote: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. AndreiI 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.
May 18 2009
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
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
On Mon, 18 May 2009 14:37:51 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Steven Schveighoffer wrote: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. -SteveBack 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.
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! Andreitemplate 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) { =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 overheadIf 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: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); } } AndreiOk, 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! Andreitemplate 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
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
Frits van Bommel wrote:Andrei Alexandrescu wrote:Damn. I meant to NOT inherit from A. AndreiGood 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
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=aexisted, we're ready to start some serious butt-kick reflection facilitie=s.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
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
在 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: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/...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 19 2009
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
Jarrett Billingsley wrote:On Mon, May 18, 2009 at 12:12 PM, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote: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! AndreiHave at it!Well? Where's my cookie? ;)
May 18 2009
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
Guillaume B. wrote:Andrei Alexandrescu wrote:"A simple matter of programming." It's a great idea, and a means to tap into AOP-style programming by using reflection. AndreiFor 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.
May 22 2009