www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Why do meta programming with templates?

reply BCS <BCS_member pathlink.com> writes:
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
next sibling parent reply James Dunne <james.jdunne gmail.com> writes:
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
parent reply Sean Kelly <sean f4.ca> writes:
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
parent reply BCS <BCS_member pathlink.com> writes:
Sean Kelly wrote:
 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
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?
Jan 24 2006
parent reply Sean Kelly <sean f4.ca> writes:
BCS wrote:
 Sean Kelly wrote:
 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.
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?
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 ); }
Jan 24 2006
next sibling parent reply Tom S <h3r3tic remove.mat.uni.torun.pl> writes:
Sean Kelly wrote:
 BCS wrote:
 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.
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 +/
Jan 24 2006
next sibling parent reply James Dunne <james.jdunne gmail.com> writes:
Tom S wrote:
 Sean Kelly wrote:
 
 BCS wrote:

 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.
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
parent reply Tom S <h3r3tic remove.mat.uni.torun.pl> writes:
James Dunne wrote:
 Tom S 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.
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).
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 +/
Jan 24 2006
parent James Dunne <james.jdunne gmail.com> writes:
Tom S wrote:
 James Dunne wrote:
 
 Tom S 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.
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).
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
Ah geezz... -- Regards, James Dunne
Jan 24 2006
prev sibling parent David Medlock <noone nowhere.com> writes:
Tom S wrote:
 Sean Kelly wrote:
 
 BCS wrote:

 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.
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.
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. -DavidM
Jan 24 2006
prev sibling parent Sean Kelly <sean f4.ca> writes:
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
prev sibling next sibling parent reply Don Clugston <dac nospam.com.au> writes:
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) Statement
 AggregateTypeExpression
     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
parent reply xs0 <xs0 xs0.com> writes:
 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
parent reply Don Clugston <dac nospam.com.au> writes:
xs0 wrote:
 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?
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.
Jan 24 2006
parent reply Agent Orange <Agent_member pathlink.com> writes:
In article <dr53e6$1mpu$1 digitaldaemon.com>, Don Clugston says...
xs0 wrote:
 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?
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.
typeof(super) ?
Jan 24 2006
parent reply Don Clugston <dac nospam.com.au> writes:
Agent Orange wrote:
 In article <dr53e6$1mpu$1 digitaldaemon.com>, Don Clugston says...
 
xs0 wrote:

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?
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.
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.
Jan 24 2006
parent reply xs0 <xs0 xs0.com> writes:
 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.
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.. xs0
Jan 24 2006
parent reply Don Clugston <dac nospam.com.au> writes:
xs0 wrote:
 
 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.
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...
void.superof would have to be illegal. In fact, I think .superof would probably be illegal for anything that is not a class/struct.
 
 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
parent reply xs0 <xs0 xs0.com> writes:
 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) { ... }
OK then, I guess my problem is solvable already.. You really are the man when it comes to D templates :) xs0
Jan 24 2006
parent pragma <pragma_member pathlink.com> writes:
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
prev sibling parent reply "Craig Black" <cblack ara.com> writes:
 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
parent reply Sean Kelly <sean f4.ca> writes:
Craig Black 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?
If this were the case, perhaps reflection API could be added to the standard library rather than the language core.
The library will support whatever it can, given language support. I'm already planning a reflection module for Ares. Sean
Jan 24 2006
parent Sean Kelly <sean f4.ca> writes:
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