digitalmars.D - Why do meta programming with templates?
- BCS (74/74) Jan 23 2006 Why is meta programming being done with templates? I have seen a number ...
- James Dunne (6/104) Jan 23 2006 Compile-time code generation! Another one of those great features that
- Sean Kelly (7/11) Jan 23 2006 It certainly beats the heck out of merely hoping that the compiler will
- BCS (7/29) Jan 24 2006 Examples please? What other functionality would be useful? What other me...
- Sean Kelly (117/146) Jan 24 2006 Pretty much. The goal is to be able to generate optimal code at
- Tom S (14/22) Jan 24 2006 I'm getting the impression that we're trying to clone the language
- James Dunne (5/29) Jan 24 2006 If I'm not mistaken, that was mine =P. Use the colon operator to
- Tom S (13/28) Jan 24 2006 Sorry to disappoint you, James, but that wasn't your proposal :P It was
- James Dunne (5/35) Jan 24 2006 Ah geezz...
- David Medlock (5/28) Jan 24 2006 They already have such a thing in Common Lisp and Scheme. Its called a
- Sean Kelly (8/15) Jan 24 2006 By the way... I'd originally hoped to do this using a switch statement
- Don Clugston (56/89) Jan 24 2006 I think there are so many meta programming possibilities that an
- xs0 (3/27) Jan 24 2006 don't forget .superof, returning the super class for classes.. Or did I
- Don Clugston (11/39) Jan 24 2006 You're right.
- Agent Orange (2/41) Jan 24 2006 typeof(super) ?
- Don Clugston (9/57) Jan 24 2006 Ah!
- xs0 (33/46) Jan 24 2006 Well, besides RTTI (CTTI? :), I was hoping to be able to do this:
- Don Clugston (27/86) Jan 24 2006 void.superof would have to be illegal. In fact, I think .superof would
- Craig Black (3/7) Jan 24 2006 If this were the case, perhaps reflection API could be added to the stan...
- Sean Kelly (4/11) Jan 24 2006 The library will support whatever it can, given language support. I'm
- Sean Kelly (3/6) Jan 24 2006 Er, I meant traits module.
Why is meta programming being done with templates? I have seen a number of vary nice things done with that technique but it seems to me to be a terribly convoluted way to go about it. Why not place some of the functionality right in the language it's self? One construct that would be vary useful is described below: --------------- WitheachStatement: witheach (WitheachTypeList; AggregateTypeExpression) Statement WitheachTypeList: AliasIdentifier AliasIdentifier inout alias Identifier inout alias Identifier AggregateTypeExpression classExpression structExpression Statement is parsed once for each member of AggregateTypeExpression with AliasIdentifier defined as an alias to the current member. For all members, Statement must be semantically ccorrect. static if statements inside of Statement are evaluated per-member. Different members of AggregateTypeExpression can be of different types and need not be converted to a common type. <code> struct A { int j; char c; double f; } A a; char[] ret = ""; witheach(alias i; a) { static if(is(c:char)) { ret ~= i; } else { ret += toString(i); } } </code> is equivalent to: <code> struct A { int j; char c; double f; } A a; char[] ret = ""; ret ~= toString(a.j); ret ~= char a.c; ret ~= toString(a.f); </code> Uses: With a set functions for the native types that converts data between native and big enden encoding, a simple function can be written that will convert all of the members of a structure from big enden to native encoding. The advantage to this is that when a new member is added the function will automatically convert it also. PortableDataStructure ConBigEnden(PortableDataStructure in) { witheach(inout alias i; in) { i = ConBigEnden(i); } return in; } p.s. The subject line of this post is NOT a rhetorical question. If there is a reason to use templates, I would be interested in hearing why. Also the above is just a suggested syntax, so feel free to point out flaw, improvements, etc.
Jan 23 2006
BCS wrote:Why is meta programming being done with templates? I have seen a number of vary nice things done with that technique but it seems to me to be a terribly convoluted way to go about it. Why not place some of the functionality right in the language it's self? One construct that would be vary useful is described below: --------------- WitheachStatement: witheach (WitheachTypeList; AggregateTypeExpression) Statement WitheachTypeList: AliasIdentifier AliasIdentifier inout alias Identifier inout alias Identifier AggregateTypeExpression classExpression structExpression Statement is parsed once for each member of AggregateTypeExpression with AliasIdentifier defined as an alias to the current member. For all members, Statement must be semantically ccorrect. static if statements inside of Statement are evaluated per-member. Different members of AggregateTypeExpression can be of different types and need not be converted to a common type. <code> struct A { int j; char c; double f; } A a; char[] ret = ""; witheach(alias i; a) { static if(is(c:char)) { ret ~= i; } else { ret += toString(i); } } </code> is equivalent to: <code> struct A { int j; char c; double f; } A a; char[] ret = ""; ret ~= toString(a.j); ret ~= char a.c; ret ~= toString(a.f); </code> Uses: With a set functions for the native types that converts data between native and big enden encoding, a simple function can be written that will convert all of the members of a structure from big enden to native encoding. The advantage to this is that when a new member is added the function will automatically convert it also. PortableDataStructure ConBigEnden(PortableDataStructure in) { witheach(inout alias i; in) { i = ConBigEnden(i); } return in; } p.s. The subject line of this post is NOT a rhetorical question. If there is a reason to use templates, I would be interested in hearing why. Also the above is just a suggested syntax, so feel free to point out flaw, improvements, etc.Compile-time code generation! Another one of those great features that I've been kicking around for my own little language. This gives me a few ideas for syntax. I like your thinking! Keep it up. Regards, James Dunne
Jan 23 2006
James Dunne wrote:Compile-time code generation! Another one of those great features that I've been kicking around for my own little language. This gives me a few ideas for syntax. I like your thinking! Keep it up.It certainly beats the heck out of merely hoping that the compiler will inline recursive function calls, which is how this is normally done. But it would need to be a bit more flexible to be ideal. For example, I'd like to be able to iterate across typelists this way, to automate factory class generation. Sean
Jan 23 2006
Sean Kelly wrote:James Dunne wrote:Don Clugston wrote:Compile-time code generation! Another one of those great features that I've been kicking around for my own little language. This gives me a few ideas for syntax. I like your thinking! Keep it up.It certainly beats the heck out of merely hoping that the compiler will inline recursive function calls, which is how this is normally done. But it would need to be a bit more flexible to be ideal. For example, I'd like to be able to iterate across typelists this way, to automate factory class generation. SeanI think there are so many meta programming possibilities that an enormous number of features would need to be added to the language. But it's definitely worth considering which things are currently convoluted, and whether simplifications are possible. The example you provide is currently not possible at all with meta programming:Examples please? What other functionality would be useful? What other meta programming tasks are commonly needed that templates can't do? I think there is a need for a whole set of statement (meta-statements?) along this line. I am still wondering why templates are being used for this. Is it just that they are the only tool at hand?
Jan 24 2006
BCS wrote:Sean Kelly wrote:Pretty much. The goal is to be able to generate optimal code at compile-time with minimal user effort... and to do so using language features instead of a fancy IDE. There have been a number of books written on the subject, but my two favorites are "Modern C++ Design" by Alexander Alexandrescu and "Generative Programming" by Czarnecki and Eisenecker. For a practical example, here's some code I posted to comp.lang.c++.moderated about five years ago (I love google): -------------------------------------------------------------------------------- This is the final version of my test code. The idea is that I wanted to be able to specify the allowable classes a factory could construct at the time of declaration -- I've got a library class that needs a list of acceptable pre-defined classes which it can construct for its own internal use. To this end, I didn't want to force the user to call register methods or any other code-based means of specifying factory classes. I used Loki to construct a factory to do this... its only downside is that the nature of the function expansion means that every call will scan the list in linear time. I've got a map-based version mostly built, but it will need to hold instances of the classes and call a Clone method, which requires memory overhead I'd currently rather avoid. In any case, I hope someone finds this useful. Just a bit more exploration of some nifty things templates can do: //////////////////////////////////////////////////////////////////////////////// #include <string> #include <iostream> #include <Typelist.h> //////////////////////////////////////////////////////////////////////////////// template<const char** Name, class Type> struct index_pair { static const char* name; typedef Type type; }; template<const char** Name, class Type> const char* index_pair<Name,Type>::name = *Name; //////////////////////////////////////////////////////////////////////////////// template<class Base, class TList, int Default, int ListSize = Loki::TL::Length<TList>::value> struct MyFactory { inline static Base* MakeNew( int index = Default ) { assert( index < ListSize ); if( index == (ListSize-1) ) return( new Loki::TL::TypeAt<TList,ListSize-1>::Result::type() ); else return( MyFactory<Base,TList,Default,ListSize-1>::MakeNew( index ) ); } inline static Base* MakeNew( const std::string& name ) { if( name == Loki::TL::TypeAt<TList,ListSize-1>::Result::name ) return( new Loki::TL::TypeAt<TList,ListSize-1>::Result::type() ); else return( MyFactory<Base,TList,Default,ListSize-1>::MakeNew( name ) ); } }; template<class Base, class TList, int Default> struct MyFactory<Base,TList,Default,0> { inline static Base* MakeNew( int index = Default ) { return( NULL ); } inline static Base* MakeNew( const std::string& name ) { return( NULL ); } }; //////////////////////////////////////////////////////////////////////////////// struct base { virtual ~base() {} virtual void operator()() { std::cout << "base\n"; } }; struct derived1 : public base { virtual void operator()() { std::cout << "derived1\n"; } }; struct derived2 : public base { virtual void operator()() { std::cout << "derived2\n"; } }; struct derived3 : public base { virtual void operator()() { std::cout << "derived3\n"; } }; const char* base_name = "base"; const char* derived1_name = "derived1"; const char* derived2_name = "derived2"; const char* derived3_name = "derived3"; int main( int argc, char **argv ) { typedef index_pair<&base_name,base> base_pair; typedef index_pair<&derived1_name,derived1> derived1_pair; typedef index_pair<&derived2_name,derived2> derived2_pair; typedef index_pair<&derived3_name,derived3> derived3_pair; typedef MyFactory<base,TYPELIST_4(base_pair,derived1_pair,derived2_pair,derived3_pair),1> fact; base* b1 = fact::MakeNew(); base* b2 = fact::MakeNew( 0 ); base* b3 = fact::MakeNew( 1 ); base* b4 = fact::MakeNew( 2 ); base* b5 = fact::MakeNew( "base" ); (*b1)(); (*b2)(); (*b3)(); (*b4)(); (*b5)(); return( 0 ); }James Dunne wrote:Don Clugston wrote: > > I think there are so many meta programming possibilities that an > enormous number of features would need to be added to the language. > But it's definitely worth considering which things are currently > convoluted, and whether simplifications are possible. > > The example you provide is currently not possible at all with meta > programming: Examples please? What other functionality would be useful? What other meta programming tasks are commonly needed that templates can't do? I think there is a need for a whole set of statement (meta-statements?) along this line. I am still wondering why templates are being used for this. Is it just that they are the only tool at hand?Compile-time code generation! Another one of those great features that I've been kicking around for my own little language. This gives me a few ideas for syntax. I like your thinking! Keep it up.It certainly beats the heck out of merely hoping that the compiler will inline recursive function calls, which is how this is normally done. But it would need to be a bit more flexible to be ideal. For example, I'd like to be able to iterate across typelists this way, to automate factory class generation.
Jan 24 2006
Sean Kelly wrote:BCS wrote:I'm getting the impression that we're trying to clone the language functionality into the compile-time part. We had a nifty proposal some time ago which, if implemented, might ease the pain. The idea was to allow a special modifier for functions which would say that they could be evaluated at compile-time. Thus the code would look just like ordinary runtime code, but being executed at compile-time. -- -----BEGIN GEEK CODE BLOCK----- Version: 3.1 GCS/M d-pu s+: a-->----- C+++$>++++ UL P+ L+ E--- W++ N++ o? K? w++ !O !M V? PS- PE- Y PGP t 5 X? R tv-- b DI- D+ G e>+++ h>++ !r !y ------END GEEK CODE BLOCK------ Tomasz Stachowiak /+ a.k.a. h3r3tic +/I am still wondering why templates are being used for this. Is it just that they are the only tool at hand?Pretty much. The goal is to be able to generate optimal code at compile-time with minimal user effort... and to do so using language features instead of a fancy IDE.
Jan 24 2006
Tom S wrote:Sean Kelly wrote:If I'm not mistaken, that was mine =P. Use the colon operator to differentiate compile-time properties from run-time properties! Either that or it was my '{%' ... '%}' block idea which was to execute code at compile time (though I never proposed this for D).BCS wrote:I'm getting the impression that we're trying to clone the language functionality into the compile-time part. We had a nifty proposal some time ago which, if implemented, might ease the pain. The idea was to allow a special modifier for functions which would say that they could be evaluated at compile-time. Thus the code would look just like ordinary runtime code, but being executed at compile-time.I am still wondering why templates are being used for this. Is it just that they are the only tool at hand?Pretty much. The goal is to be able to generate optimal code at compile-time with minimal user effort... and to do so using language features instead of a fancy IDE.
Jan 24 2006
James Dunne wrote:Tom S wrote:Sorry to disappoint you, James, but that wasn't your proposal :P It was Bill Baxter who originally started the discussion here: http://www.digitalmars.com/d/archives/digitalmars/D/23175.html Eventually, Walter commented: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/24126 -- -----BEGIN GEEK CODE BLOCK----- Version: 3.1 GCS/M d-pu s+: a-->----- C+++$>++++ UL P+ L+ E--- W++ N++ o? K? w++ !O !M V? PS- PE- Y PGP t 5 X? R tv-- b DI- D+ G e>+++ h>++ !r !y ------END GEEK CODE BLOCK------ Tomasz Stachowiak /+ a.k.a. h3r3tic +/I'm getting the impression that we're trying to clone the language functionality into the compile-time part. We had a nifty proposal some time ago which, if implemented, might ease the pain. The idea was to allow a special modifier for functions which would say that they could be evaluated at compile-time. Thus the code would look just like ordinary runtime code, but being executed at compile-time.If I'm not mistaken, that was mine =P. Use the colon operator to differentiate compile-time properties from run-time properties! Either that or it was my '{%' ... '%}' block idea which was to execute code at compile time (though I never proposed this for D).
Jan 24 2006
Tom S wrote:James Dunne wrote:Ah geezz... -- Regards, James DunneTom S wrote:Sorry to disappoint you, James, but that wasn't your proposal :P It was Bill Baxter who originally started the discussion here: http://www.digitalmars.com/d/archives/digitalmars/D/23175.html Eventually, Walter commented: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/24126I'm getting the impression that we're trying to clone the language functionality into the compile-time part. We had a nifty proposal some time ago which, if implemented, might ease the pain. The idea was to allow a special modifier for functions which would say that they could be evaluated at compile-time. Thus the code would look just like ordinary runtime code, but being executed at compile-time.If I'm not mistaken, that was mine =P. Use the colon operator to differentiate compile-time properties from run-time properties! Either that or it was my '{%' ... '%}' block idea which was to execute code at compile time (though I never proposed this for D).
Jan 24 2006
Tom S wrote:Sean Kelly wrote:They already have such a thing in Common Lisp and Scheme. Its called a macro, and its the thing most Lispers refuse to give up to take another language. -DavidMBCS wrote:I'm getting the impression that we're trying to clone the language functionality into the compile-time part. We had a nifty proposal some time ago which, if implemented, might ease the pain. The idea was to allow a special modifier for functions which would say that they could be evaluated at compile-time. Thus the code would look just like ordinary runtime code, but being executed at compile-time.I am still wondering why templates are being used for this. Is it just that they are the only tool at hand?Pretty much. The goal is to be able to generate optimal code at compile-time with minimal user effort... and to do so using language features instead of a fancy IDE.
Jan 24 2006
Sean Kelly wrote:I used Loki to construct a factory to do this... its only downside is that the nature of the function expansion means that every call will scan the list in linear time. I've got a map-based version mostly built, but it will need to hold instances of the classes and call a Clone method, which requires memory overhead I'd currently rather avoid.By the way... I'd originally hoped to do this using a switch statement instead of recursion, but this doesn't really work with C++ templates. I'm not sure if it would work with D templates (I'd have to think about it a bit), but something like witheach should make this possible as each case statement could be generated inline. It would be darn nice to have something like this, as the resulting code would be extremely fast. Sean
Jan 24 2006
BCS wrote:Why is meta programming being done with templates? I have seen a number of vary nice things done with that technique but it seems to me to be a terribly convoluted way to go about it. Why not place some of the functionality right in the language it's self?I think there are so many meta programming possibilities that an enormous number of features would need to be added to the language. But it's definitely worth considering which things are currently convoluted, and whether simplifications are possible. The example you provide is currently not possible at all with meta programming:WitheachStatement: witheach (WitheachTypeList; AggregateTypeExpression) StatementAggregateTypeExpression classExpression structExpression<code> struct A { int j; char c; double f; } A a; char[] ret = ""; witheach(alias i; a) { static if(is(c:char)) { ret ~= i; } else { ret += toString(i); } } </code>I think this actually an example of two things: (a) compile-time reflection. (b) compile-time for loops. Currently there's no way to determine the members of a class, struct, module or function at compile-time. Definitely, some form of compile-time reflection would be very cool. A limitation of this witheach() syntax is that (for example) it doesn't give you any way of determining at compile time how many members there are in the struct. There's no such thing as a compile-time variable, for example, so looping constructs won't work very well without some major additions to the language. Here's a first pass at how I'd do this with metaprogramming: ------ template makeString(X, int n=0) { char [] makeString(X x) { static if (X.membercount == n) return ""; else static if (X.memberof[n].membercount>0) // deal with case where a member is itself a struct return makeString!( X.memberof[n] )(x.memberof[n]) ~ makeString!(X, n+1)(x); else static if ( is (X.memberof[n] : char) ) return x.memberof[n] ~ makeString!(X, n+1); else return toString(x.memberof[n]) ~ makeString!(X, n+1)(x); } } A a; char[] ret = "" ~ makeString!(X)(x); ---------- I don't think that's too terrible, considering that it copes with the nested struct situation. For this to work, every expression T would need several new properties: .membercount which gives the number of members it has (0 = it is a fundamental type) .memberof[int n] which gives the nth member. If T is a type, gives that type; if it's an instance, gives a reference to that member. (This might need to be split into two properties; I'm not sure). And for completeness: .parentof same, except gives the class/module it's nested in. void if no parent (ie, it is a package). I think that these three properties would give D everything at compile time, that .NET reflection offers at runtime! (When combined with DDL, for run-time linking). And reflection is much more powerful at compile time than run time. Hmm, might work this into a compile-time reflection proposal.
Jan 24 2006
For this to work, every expression T would need several new properties: ..membercount which gives the number of members it has (0 = it is a fundamental type) ..memberof[int n] which gives the nth member. If T is a type, gives that type; if it's an instance, gives a reference to that member. (This might need to be split into two properties; I'm not sure). And for completeness: ..parentof same, except gives the class/module it's nested in. void if no parent (ie, it is a package). I think that these three properties would give D everything at compile time, that .NET reflection offers at runtime! (When combined with DDL, for run-time linking). And reflection is much more powerful at compile time than run time. Hmm, might work this into a compile-time reflection proposal.don't forget .superof, returning the super class for classes.. Or did I miss it and it already exists? xs0
Jan 24 2006
xs0 wrote:You're right. Aargh, there's interfaces too, which can be variable in number, just like members. Right now, because there's no implicit template instantiation, we can't do function parameters properly, but we can get close. We can do all built-in types, and for classes, structs and typedefs, we can get their name as a const char [] text string (just not as a type). Similarly, for .parentof, in most cases we can already get the name of the parent as a const char [], but that is no use for wandering the syntax trees at compile time.For this to work, every expression T would need several new properties: ..membercount which gives the number of members it has (0 = it is a fundamental type) ..memberof[int n] which gives the nth member. If T is a type, gives that type; if it's an instance, gives a reference to that member. (This might need to be split into two properties; I'm not sure). And for completeness: ..parentof same, except gives the class/module it's nested in. void if no parent (ie, it is a package). I think that these three properties would give D everything at compile time, that .NET reflection offers at runtime! (When combined with DDL, for run-time linking). And reflection is much more powerful at compile time than run time. Hmm, might work this into a compile-time reflection proposal.don't forget .superof, returning the super class for classes.. Or did I miss it and it already exists?
Jan 24 2006
In article <dr53e6$1mpu$1 digitaldaemon.com>, Don Clugston says...xs0 wrote:typeof(super) ?You're right. Aargh, there's interfaces too, which can be variable in number, just like members. Right now, because there's no implicit template instantiation, we can't do function parameters properly, but we can get close. We can do all built-in types, and for classes, structs and typedefs, we can get their name as a const char [] text string (just not as a type). Similarly, for .parentof, in most cases we can already get the name of the parent as a const char [], but that is no use for wandering the syntax trees at compile time.For this to work, every expression T would need several new properties: ..membercount which gives the number of members it has (0 = it is a fundamental type) ..memberof[int n] which gives the nth member. If T is a type, gives that type; if it's an instance, gives a reference to that member. (This might need to be split into two properties; I'm not sure). And for completeness: ..parentof same, except gives the class/module it's nested in. void if no parent (ie, it is a package). I think that these three properties would give D everything at compile time, that .NET reflection offers at runtime! (When combined with DDL, for run-time linking). And reflection is much more powerful at compile time than run time. Hmm, might work this into a compile-time reflection proposal.don't forget .superof, returning the super class for classes.. Or did I miss it and it already exists?
Jan 24 2006
Agent Orange wrote:In article <dr53e6$1mpu$1 digitaldaemon.com>, Don Clugston says...Ah! That almost works. You just need to add: alias typeof(super) superof; to the definition of every class. It does not seem possible to obtain it otherwise. You cannot use a dot syntax, for example. (can't even say this.super), so unfortunately you cannot say super.super with any arrangement of typeof() that I can come up with.xs0 wrote:typeof(super) ?You're right. Aargh, there's interfaces too, which can be variable in number, just like members. Right now, because there's no implicit template instantiation, we can't do function parameters properly, but we can get close. We can do all built-in types, and for classes, structs and typedefs, we can get their name as a const char [] text string (just not as a type). Similarly, for .parentof, in most cases we can already get the name of the parent as a const char [], but that is no use for wandering the syntax trees at compile time.For this to work, every expression T would need several new properties: ..membercount which gives the number of members it has (0 = it is a fundamental type) ..memberof[int n] which gives the nth member. If T is a type, gives that type; if it's an instance, gives a reference to that member. (This might need to be split into two properties; I'm not sure). And for completeness: ..parentof same, except gives the class/module it's nested in. void if no parent (ie, it is a package). I think that these three properties would give D everything at compile time, that .NET reflection offers at runtime! (When combined with DDL, for run-time linking). And reflection is much more powerful at compile time than run time. Hmm, might work this into a compile-time reflection proposal.don't forget .superof, returning the super class for classes.. Or did I miss it and it already exists?
Jan 24 2006
Well, besides RTTI (CTTI? :), I was hoping to be able to do this: class List(T) : List!(T.superof) { } with the idea that a List of Whatevers is also a List of Objects, but is not assignable as such. typeof(super) wouldn't work, I guess, because I want T's super, not List's, and super is probably defined only inside the class anyway. Even if it did work, the compiler would need to specifically handle this idiom, as the above code contains an infinite loop: T->...->Object->void->void->void... Come to think of it, would it be awfully weird, if the class hierarchy could be defined conditionally from within the class, not only where it's declared? Something like: class List(T) { static if (is(T:Object) && !is(T==Object)) { this class : List!(T.superof); } } or class Foo(T) { static if (is(T:Serializable)) { this class : Serializable; } else { this class : PartiallySerializable; } } With the meaning that Foo!(T) is only serializable, if T is.. It would also allow backward compatible refactoring of class hierarchies, as an older version of the app wouldn't even need to know the class has moved, for example.. xs0typeof(super) ?Ah! That almost works. You just need to add: alias typeof(super) superof; to the definition of every class. It does not seem possible to obtain it otherwise. You cannot use a dot syntax, for example. (can't even say this.super), so unfortunately you cannot say super.super with any arrangement of typeof() that I can come up with.
Jan 24 2006
xs0 wrote:void.superof would have to be illegal. In fact, I think .superof would probably be illegal for anything that is not a class/struct.Well, besides RTTI (CTTI? :), I was hoping to be able to do this: class List(T) : List!(T.superof) { } with the idea that a List of Whatevers is also a List of Objects, but is not assignable as such. typeof(super) wouldn't work, I guess, because I want T's super, not List's, and super is probably defined only inside the class anyway. Even if it did work, the compiler would need to specifically handle this idiom, as the above code contains an infinite loop: T->...->Object->void->void->void...typeof(super) ?Ah! That almost works. You just need to add: alias typeof(super) superof; to the definition of every class. It does not seem possible to obtain it otherwise. You cannot use a dot syntax, for example. (can't even say this.super), so unfortunately you cannot say super.super with any arrangement of typeof() that I can come up with.Come to think of it, would it be awfully weird, if the class hierarchy could be defined conditionally from within the class, not only where it's declared? Something like: class List(T) { static if (is(T:Object) && !is(T==Object)) { this class : List!(T.superof); } }Providing you put the superof alias in your classes, you can already do (since it's legal to derive from Object): template ListBaseClass(T) { static if( is(T: Object) && !is(T==Object)) alias T.superof ListBaseClass; else alias Object ListBaseClass; } template List(T) { class List : ListBaseClass!(T) { .... } }or class Foo(T) { static if (is(T:Serializable)) { this class : Serializable; } else { this class : PartiallySerializable; } }template FooBaseClass(T) { static if( is(T: Serializable)) alias Serializable FooBaseClass; else alias PartiallySerializable FooBaseClass; } class Foo(T) : public FooBaseClass!(T) { ... }With the meaning that Foo!(T) is only serializable, if T is.. It would also allow backward compatible refactoring of class hierarchies, as an older version of the app wouldn't even need to know the class has moved, for example.. xs0
Jan 24 2006
Providing you put the superof alias in your classes, you can already do (since it's legal to derive from Object): template ListBaseClass(T) { static if( is(T: Object) && !is(T==Object)) alias T.superof ListBaseClass; else alias Object ListBaseClass; } template List(T) { class List : ListBaseClass!(T) { .... } }OK then, I guess my problem is solvable already.. You really are the man when it comes to D templates :) xs0or class Foo(T) { static if (is(T:Serializable)) { this class : Serializable; } else { this class : PartiallySerializable; } }template FooBaseClass(T) { static if( is(T: Serializable)) alias Serializable FooBaseClass; else alias PartiallySerializable FooBaseClass; } class Foo(T) : public FooBaseClass!(T) { ... }
Jan 24 2006
In article <dr5ml8$29vf$1 digitaldaemon.com>, xs0 says...OK then, I guess my problem is solvable already.. You really are the man when it comes to D templates :)I do believe you mean "Template Ninja". Seriously. The man enacts strikes of template ninjitsu with an unmatched level of cunning and skill. - EricAnderton at yahoo
Jan 24 2006
Why is meta programming being done with templates? I have seen a number of vary nice things done with that technique but it seems to me to be a terribly convoluted way to go about it. Why not place some of the functionality right in the language it's self?If this were the case, perhaps reflection API could be added to the standard library rather than the language core. -Craig
Jan 24 2006
Craig Black wrote:The library will support whatever it can, given language support. I'm already planning a reflection module for Ares. SeanWhy is meta programming being done with templates? I have seen a number of vary nice things done with that technique but it seems to me to be a terribly convoluted way to go about it. Why not place some of the functionality right in the language it's self?If this were the case, perhaps reflection API could be added to the standard library rather than the language core.
Jan 24 2006
Sean Kelly wrote:The library will support whatever it can, given language support. I'm already planning a reflection module for Ares.Er, I meant traits module. Sean
Jan 24 2006