January 17, 2006
Whoa .. hold on there!
The class idea was a *hack* only! The real solution is not to integrate that "hack" into the language, but to add a way to convert an identifier name to a string at compile time, which should be easy for the compiler to do!!

I mean .. why would you want to convert a string to an identifier .. only to convert it back to a string again!!


Don Clugston wrote:
> Hasan Aljudy wrote:
> 
>> pragma wrote:
>>
>>>> I was thinking more of creating a class inside the template, where the class name will be the supplied parameter (identifier).
>>>> I guess that isn't possible .. is it?
>>>
>>>
>>>
>>>
>>> Do you mean like reflection?  We're not quite there yet, but there is
>>> considerable demand for such a feature: you're not alone.
>>>
>>> - EricAnderton at yahoo
>>
>>
>>
>> Not really, I was thinking in terms of template .. i.e.
>>
>> ##
>> template createclass( T )
>> {
>>     class T
>>     {
>>     }
>> }
>>
>> ...
>> mixin createclass!( ANewClassName ); //create a class called ANewClassName
>> ##
>>
>> but I discovered that it's not possible in D.
> 
> 
> In general it's not possible. There's an interesting case where it is possible, but you have to do it manually:
> 
> template createclass(char [] name)
> {
>   static if (name[0]=='a') {
>     class a { }
>   else static if (name[0]=='b') {
>     class b { }
>   else static if (name[0]=='c') {
>     class c { }
>   } else static assert(0); // name not supported
> }
> 
> mixin createclass!("a");
> 
> Of course, this is not much use. But it is an argument that a more general facility could be provided in the language without causing new problems.
> 
> If the next line of code was
> 
> a.somefunc();
> 
> an intellisense IDE is going to have a lot of trouble making sense of a. Since this problem already exists, it should reduce objection to the following proposal:
> 
> 
> I'd like to see the definition of Identifier changed to:
> 
> Identifier:
>    IdentifierStart
>    IdentifierStart IdentifierChars
>    identifier(StringLiteral)
> 
> so that whereever you write
> 
> abc
> 
> you could also write
> 
> identifier("abc")
> 
> During the semantic pass, whenever identifier( _stringexpr_ ) is encountered, it would be replaced with _stringexpr_.
> 
> In your case, it would let you write
> 
> class identifier("ANewClassName")
> {
> }
> 
> identifier("ANewClassName") identifier("x") = new identifier("ANewClassName");
> 
> Which would be completely useless, except that D provides compile-time string processing, so that the string literals could be created from constant strings.
> We'd have the equivalent of the C/C++ 'stringize' preprocessor operator, but fully integrated into the template system, and without wrecking the lexical and syntactic passes.
> 
> Just need a 'tokenize' operator -- eg
> 
> qualifiednameof(Identifier)
> 
> eg
> const char [] y = qualifiednameof(x);
> static assert( y == "somemodule.SomeClass.someFunc.x");
> 
> This would mean that D templates would finally encompass all the functionality of the C++ preprocessor.
> 
> 
> A future step would be to add
> 
> const char [][] membersof(Identifier)
> 
> returning an array of all the names which were declared in the scope of Identifier. (although, this last one would not be useful until D gets array literals). Then we'd have full compile-time reflection, and the ability to dump arbitrary code into the optimiser based on the results.
> 
> Undoubtedly far too much rope.
> :-)
> 
January 17, 2006
Hasan Aljudy wrote:
> Whoa .. hold on there!
> The class idea was a *hack* only! The real solution is not to integrate that "hack" into the language, but to add a way to convert an identifier name to a string at compile time, which should be easy for the compiler to do!!

Yes, that's the purpose of the suggested qualifiednameof() operator, which is far less controversial than my other suggestion.

I got a bit carried away, because I've been thinking about the general case -- how could D provide ALL the capabilities of the C++ preprocessor?

> I mean .. why would you want to convert a string to an identifier .. only to convert it back to a string again!!

You wouldn't. But you might might convert an identifier to a string, manipulate the string, then convert it to another identifier. For example,

module somemodule;

int somefunc()
{
   real x;
   const char [] s = qualifiednameof(x);
// assert(s == "somemodule.somefunc.x")

   // Extract the name of the enclosing function

   const char [] selffuncname = split!(s, '.', 1);
   // assert(selffuncname == "somefunc")

// Now get a function pointer to ourself...
   int function () selfptr = &__identifier(selffuncname);
}

Not a very sensible example. I'm just trying to illustrate that these functions would provide compile-time reflection.
( split!() is a function from my meta.string metaprogramming library; it behaves exactly like std.string.split, except that it works at compile time).

Something like qualifiednameof() I think would be generally useful (apart from sophisticated uses, it would be great for error messages). And it seems to be harmless.

(However, the __identifier() thing requires more thought, because it would be an extremely powerful and dangerous feature).

> 
> Don Clugston wrote:
> 
>> Hasan Aljudy wrote:
>>
>>> pragma wrote:
>>>
>>>>> I was thinking more of creating a class inside the template, where the class name will be the supplied parameter (identifier).
>>>>> I guess that isn't possible .. is it?
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> Do you mean like reflection?  We're not quite there yet, but there is
>>>> considerable demand for such a feature: you're not alone.
>>>>
>>>> - EricAnderton at yahoo
>>>
>>>
>>>
>>>
>>> Not really, I was thinking in terms of template .. i.e.
>>>
>>> ##
>>> template createclass( T )
>>> {
>>>     class T
>>>     {
>>>     }
>>> }
>>>
>>> ...
>>> mixin createclass!( ANewClassName ); //create a class called ANewClassName
>>> ##
>>>
>>> but I discovered that it's not possible in D.
>>
>>
>>
>> In general it's not possible. There's an interesting case where it is possible, but you have to do it manually:
>>
>> template createclass(char [] name)
>> {
>>   static if (name[0]=='a') {
>>     class a { }
>>   else static if (name[0]=='b') {
>>     class b { }
>>   else static if (name[0]=='c') {
>>     class c { }
>>   } else static assert(0); // name not supported
>> }
>>
>> mixin createclass!("a");
>>
>> Of course, this is not much use. But it is an argument that a more general facility could be provided in the language without causing new problems.
>>
>> If the next line of code was
>>
>> a.somefunc();
>>
>> an intellisense IDE is going to have a lot of trouble making sense of a. Since this problem already exists, it should reduce objection to the following proposal:
>>
>>
>> I'd like to see the definition of Identifier changed to:
>>
>> Identifier:
>>    IdentifierStart
>>    IdentifierStart IdentifierChars
>>    identifier(StringLiteral)
>>
>> so that whereever you write
>>
>> abc
>>
>> you could also write
>>
>> identifier("abc")
>>
>> During the semantic pass, whenever identifier( _stringexpr_ ) is encountered, it would be replaced with _stringexpr_.
>>
>> In your case, it would let you write
>>
>> class identifier("ANewClassName")
>> {
>> }
>>
>> identifier("ANewClassName") identifier("x") = new identifier("ANewClassName");
>>
>> Which would be completely useless, except that D provides compile-time string processing, so that the string literals could be created from constant strings.
>> We'd have the equivalent of the C/C++ 'stringize' preprocessor operator, but fully integrated into the template system, and without wrecking the lexical and syntactic passes.
>>
>> Just need a 'tokenize' operator -- eg
>>
>> qualifiednameof(Identifier)
>>
>> eg
>> const char [] y = qualifiednameof(x);
>> static assert( y == "somemodule.SomeClass.someFunc.x");
>>
>> This would mean that D templates would finally encompass all the functionality of the C++ preprocessor.
>>
>>
>> A future step would be to add
>>
>> const char [][] membersof(Identifier)
>>
>> returning an array of all the names which were declared in the scope of Identifier. (although, this last one would not be useful until D gets array literals). Then we'd have full compile-time reflection, and the ability to dump arbitrary code into the optimiser based on the results.
>>
>> Undoubtedly far too much rope.
>> :-)
>>
January 18, 2006
John Reimer wrote:
> Garett Bass wrote:
> 
>> Is there any template means by which I can create a string representation from an identifier name at compile time?  I.e. given the identifier name i, I'd like a template that can create a string "i".  Thanks in advance for any ideas.
>>
>> Regards,
>> Garett
> 
> 
> I asked for this sort of feature in another post last year.  The compiler currently does not have this ability, although I think it's important and useful. If the D infrastructure is to be capable of replacing the preprocessors of languages like C/C++, it will need to offer some capability of this sort.  While exceedingly elegant compared to preprocessor macros, version control and templates just don't provide comprehensive functionality yet (in this particular area, anyway; templates in D are a wonderful simplification of C++ templates obfuscation).
> 
> -JJR

I've been able to hack an implementation together. The qualifiednameof!(X) metafunction gives
the mangled fully qualified name of the symbol X, which includes the complete name and some type information. Works for any symbol which is permitted as a template alias parameter (ie, won't work for module names, member variables, or local variables. But it does work for any type, template, function, global or static variable). It relies on the current name-mangling algorithm, but at least that is now documented.

http://svn.dsource.org/projects/ddl/trunk/meta/qualifiedname.d

My test program is here, which demangles the name to give something more human-readable. Please forgive the poor state of this code; it's not ready to be used elsewhere. But it demonstrates what's currently possible for compile-time reflection. It might give you some ideas...

http://svn.dsource.org/projects/ddl/trunk/meta/qualtest.d

With the declarations...
---------------------------------
class HeresAClass {
    void MemberFunc() { }
    struct AndAnInnerStruct {}
}

extern int someExternalInt;

real aStaticFunction() { return 2.5;}

HeresAClass anInstance;

template ThisIsATemplate (A) {
  int something;
}

extern (Windows) real aWindowsFunction(int a, real b) { return b; }
extern (C) real aCFunction(int a, real b) { return b; }

typedef HeresAClass TypedefClass;

enum   HeresAnEnum { Val1, Val2, Val3 };
---------------------------------
Then with statements like...

pragma(msg, describe!(HeresAClass));
pragma(msg, describe!(HeresAClass.AndAnInnerStruct));
pragma(msg, describe!(TypedefClass));
:
pragma(msg, describe!(ThisIsATemplate!(int)));

the program output is (at compile time, no exe is generated): dmd -c meta/qualtest.d


=== Compile time reflection ===

Class:   qualtest.HeresAClass
Struct:  qualtest.HeresAClass.AndAnInnerStruct
Typedef: qualtest.TypedefClass
Enum:    qualtest.HeresAnEnum

* With D linkage, the type is at the end of the name

D external: qualtest.aStaticFunction  (and type is: FZe)
D external: qualtest.HeresAClass.MemberFunc  (and type is: FZv)
D external: qualtest.anInstance  (and type is: C8qualtest11HeresAClass)
D external: qualtest.someExternalInt  (and type is: i)

* Special cases

Special: aCFunction
Special: aWindowsFunction
Special: (Template) qualtest.ThisIsATemplate
Special: (Template) qualtest.__T15ThisIsATemplateTiZ
January 18, 2006
Don Clugston wrote:

> I've been able to hack an implementation together. The qualifiednameof!(X) metafunction gives
> the mangled fully qualified name of the symbol X, which includes the complete name and some type information.
...

Very impressive, Don!

I didn't know that was possible.  Thank you.  I will check it out (literally :) ).

-JJR
January 19, 2006
Don Clugston wrote:
> John Reimer wrote:
>> Garett Bass wrote:
>>
>>> Is there any template means by which I can create a string representation from an identifier name at compile time?  I.e. given the identifier name i, I'd like a template that can create a string "i".  Thanks in advance for any ideas.
>>>
>>> Regards,
>>> Garett
>>
>>
>> I asked for this sort of feature in another post last year.  The compiler currently does not have this ability, although I think it's important and useful. If the D infrastructure is to be capable of replacing the preprocessors of languages like C/C++, it will need to offer some capability of this sort.  While exceedingly elegant compared to preprocessor macros, version control and templates just don't provide comprehensive functionality yet (in this particular area, anyway; templates in D are a wonderful simplification of C++ templates obfuscation).
>>
>> -JJR
> 
> I've been able to hack an implementation together. The qualifiednameof!(X) metafunction gives
> the mangled fully qualified name of the symbol X, which includes the complete name and some type information. Works for any symbol which is permitted as a template alias parameter (ie, won't work for module names, member variables, or local variables. But it does work for any type, template, function, global or static variable). It relies on the current name-mangling algorithm, but at least that is now documented.
> 
> http://svn.dsource.org/projects/ddl/trunk/meta/qualifiedname.d
> 
> My test program is here, which demangles the name to give something more human-readable. Please forgive the poor state of this code; it's not ready to be used elsewhere. But it demonstrates what's currently possible for compile-time reflection. It might give you some ideas...
> 
> http://svn.dsource.org/projects/ddl/trunk/meta/qualtest.d
> 
> With the declarations...
> ---------------------------------
> class HeresAClass {
>     void MemberFunc() { }
>     struct AndAnInnerStruct {}
> }
> 
> extern int someExternalInt;
> 
> real aStaticFunction() { return 2.5;}
> 
> HeresAClass anInstance;
> 
> template ThisIsATemplate (A) {
>   int something;
> }
> 
> extern (Windows) real aWindowsFunction(int a, real b) { return b; }
> extern (C) real aCFunction(int a, real b) { return b; }
> 
> typedef HeresAClass TypedefClass;
> 
> enum   HeresAnEnum { Val1, Val2, Val3 };
> ---------------------------------
> Then with statements like...
> 
> pragma(msg, describe!(HeresAClass));
> pragma(msg, describe!(HeresAClass.AndAnInnerStruct));
> pragma(msg, describe!(TypedefClass));
> :
> pragma(msg, describe!(ThisIsATemplate!(int)));
> 
> the program output is (at compile time, no exe is generated): dmd -c meta/qualtest.d
> 
> 
> === Compile time reflection ===
> 
> Class:   qualtest.HeresAClass
> Struct:  qualtest.HeresAClass.AndAnInnerStruct
> Typedef: qualtest.TypedefClass
> Enum:    qualtest.HeresAnEnum
> 
> * With D linkage, the type is at the end of the name
> 
> D external: qualtest.aStaticFunction  (and type is: FZe)
> D external: qualtest.HeresAClass.MemberFunc  (and type is: FZv)
> D external: qualtest.anInstance  (and type is: C8qualtest11HeresAClass)
> D external: qualtest.someExternalInt  (and type is: i)
> 
> * Special cases
> 
> Special: aCFunction
> Special: aWindowsFunction
> Special: (Template) qualtest.ThisIsATemplate
> Special: (Template) qualtest.__T15ThisIsATemplateTiZ


Don,

While I am very impressed at how you managed to do this, I am somewhat disturbed to see the gymnastics it took to get there.  It shouldn't be that hard to do.  If the D compiler had a simple command, property or whatever in place to accomplish the same task, we wouldn't have to go to such trouble.  I was going to use the code in a project... but I'm a little hesitant to do so at the moment.

I just about went cross-eyed trying to figure out how you managed that! lol! (in fact, I never did figure it out).

I think D history will forever remember you as the "template ninja."

-JJR
January 20, 2006
John Reimer wrote:
> Don Clugston wrote:
> 
>> I've been able to hack an implementation together. The qualifiednameof!(X) metafunction gives
>> the mangled fully qualified name of the symbol X, which includes the complete name and some type information. Works for any symbol which is permitted as a template alias parameter (ie, won't work for module names, member variables, or local variables. But it does work for any type, template, function, global or static variable).

Addition: I just discovered that it works for module names. It doesn't work for template aliases, though.

 It relies on the
>> current name-mangling algorithm, but at least that is now documented.
>>
>> http://svn.dsource.org/projects/ddl/trunk/meta/qualifiedname.d

> Don,
> 
> While I am very impressed at how you managed to do this, I am somewhat disturbed to see the gymnastics it took to get there.  It shouldn't be that hard to do.  If the D compiler had a simple command, property or whatever in place to accomplish the same task, we wouldn't have to go to such trouble.  

I agree. It's an exploration of what is _possible_. I'm using it to work out what you could do with such a feature. It seems that finding a way to hack a cool feature into the language is a good way of motivating Walter to provide a clean way of doing it <g>. It also helps to clarify how the feature needs to work.

I was going to use the code in a project... but I'm a
> little hesitant to do so at the moment.

It's certainly not ready for production. In fact I haven't released any of 'meta'. I plan on refactoring most of it into a 'meta.demangle' (equivalent to std.demangle), at which point it might look more reasonable.

> I just about went cross-eyed trying to figure out how you managed that! lol! (in fact, I never did figure it out).

I updated the code, and included some comments which should make it clearer.

> I think D history will forever remember you as the "template ninja."

<g> I'm just borrowing the mantle while Matthew is sleeping. I still feel like a D template novice. I still don't have much idea of what the limits are for what's possible. I've never used a mixin, an is() expression, or any kind of template constraint.

If you get in first, you make all the easy discoveries. (And you have the most fun). I'm sure all kinds of crazy stuff is still waiting to be found.
January 22, 2006
Wow, Don, it hasn't totally sunk in yet, but that is impressive!  My original goal was to use the string-ized identifier names in my serialization primitives.  The idea is to prevent people from typing the identifier twice, the second time as a string, which could introduce errors.  I also need the strings to disambiguate subtypes in a super-typed array.

Fortunately/Unfortunately, school has begun again, and I have several huge semester-long C/C++ projects, so it looks as though I won't be able to finish the serialization primitives until Summer.  I'll try to find some time though, because they work really well already, and they just need to go that extra polymorphic mile...

Regards,
Garett

Don Clugston wrote:
> John Reimer wrote:
>> Don Clugston wrote:
>>
>>> I've been able to hack an implementation together. The qualifiednameof!(X) metafunction gives
>>> the mangled fully qualified name of the symbol X, which includes the complete name and some type information. Works for any symbol which is permitted as a template alias parameter (ie, won't work for module names, member variables, or local variables. But it does work for any type, template, function, global or static variable).
> 
> Addition: I just discovered that it works for module names. It doesn't work for template aliases, though.
> 
>  It relies on the
>>> current name-mangling algorithm, but at least that is now documented.
>>>
>>> http://svn.dsource.org/projects/ddl/trunk/meta/qualifiedname.d
> 
>> Don,
>>
>> While I am very impressed at how you managed to do this, I am somewhat disturbed to see the gymnastics it took to get there.  It shouldn't be that hard to do.  If the D compiler had a simple command, property or whatever in place to accomplish the same task, we wouldn't have to go to such trouble.  
> 
> I agree. It's an exploration of what is _possible_. I'm using it to work out what you could do with such a feature. It seems that finding a way to hack a cool feature into the language is a good way of motivating Walter to provide a clean way of doing it <g>. It also helps to clarify how the feature needs to work.
> 
> I was going to use the code in a project... but I'm a
>> little hesitant to do so at the moment.
> 
> It's certainly not ready for production. In fact I haven't released any of 'meta'. I plan on refactoring most of it into a 'meta.demangle' (equivalent to std.demangle), at which point it might look more reasonable.
> 
>> I just about went cross-eyed trying to figure out how you managed that! lol! (in fact, I never did figure it out).
> 
> I updated the code, and included some comments which should make it clearer.
> 
>> I think D history will forever remember you as the "template ninja."
> 
> <g> I'm just borrowing the mantle while Matthew is sleeping. I still feel like a D template novice. I still don't have much idea of what the limits are for what's possible. I've never used a mixin, an is() expression, or any kind of template constraint.
> 
> If you get in first, you make all the easy discoveries. (And you have the most fun). I'm sure all kinds of crazy stuff is still waiting to be found.
1 2
Next ›   Last »