www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Template metaprogramming quirk list

reply Don Clugston <dac nospam.com.au> writes:
The items in this list mostly fall into the category of limitations 
rather than bugs; but in each case, the limitations are unintuitive.
I've listed them in order of decreasing importance.
Workarounds are also shown.

---------------------
MAJOR: Restrictions on static if in templates

Quoting the docs:
"StaticIfConditions cannot appear at module scope. They can appear in
class, template, struct, union, or function scope. In function scope,
the symbols referred to in the AssignExpression can be any that can
normally be referenced by an expression at that point. Otherwise, the
only symbols that can be referred to are up one scope level from the
condition."
...
"It does not introduce a new scope even if { }  are used for
conditionally compiled statements."

Together, these restrictions mean that a metafunction can't store
intermediate results, so that complex template code like pragma's regex 
gets quite ugly and convoluted.

Workaround: invoke the metafunction every time you want to use the 
result from it. (Sometimes this can result in a drastic increase in
the number of template instantiations required).

---------------------
MINOR: Allow concatenation char[] ~ char

Desired:
   const char [] s = "abcdef" ~ 'g';

Workaround: Ugly. Convert char to char[] by taking slices of a string 
containing all characters. Only works for char, not for wchar, dchar.

   const char [] s = "abcdef" ~ makechar!('g');

/// converts a single char to a char[]
template makechar(int c)
{
   const char [] makechar=
x"000102030405060708090a0b0c0d0e0f						 
101112131415161718191a1b1c1d1e1f						 
202122232425262728292a1b2c2d2e2f						 
303132333435363738393a3b3c3d3e3f						 
404142434445464748494a4b4c4d4e4f						 
505152535455565758595a5b5c5d5e5f						 
606162636465666768696a6b6c6d6e6f						 
707172737475767778797a7b7c7d7e7f						 
808182838485868788898a8b8c8d8e8f						 
909192939495969798999a9b9c9d9e9f						 
a0a1a2a3a4a5a6a7a8a9aaabacadaeaf						 
b0b1b2b3b4b5b6b7b8b9babbbcbdbebf						 
c0c1c2c3c4c5c6c7c8c9cacbcccdcecf						 
d0d1d2d3d4d5d6d7d8d9dadbdcdddedf						 
e0e1e2e3e4e5e6e7e8e9eaebecedeeef						 
f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"[c..c+1];
}

---------------------
AESTHETIC: The . in recursive templates.

template fact(int x)
{
   static if (x>1)  const int fact = x * .fact!(x-1);
   else const int fact = 1;
}

The dot is a workaround, only needed because the constant "fact" we're
setting is in scope.
Why is it already in the symbol table? The workaround is more complex 
when the template is not at module scope -- you need to include dot plus 
fully qualified name. The following example works:

struct outer
{
     template fact(int x)
     {
       static if (x>1)  const int fact = x * .outer.fact!(x-1);
       else const int fact = 1;
     }
     static assert(fact!(6)==8);
}

If you leave off the dot before the outer, ie
       static if (x>1)  const int fact = x * outer.fact!(x-1);
then the error message is:

  template fact!(x - 1) is not a member of outer

which is a little weird.

---------------------
MINOR: Allow compile time equality comparisions char[] == char[], char[] 
!= char[]

This would be a problem if the workaround was not so easy.


// return true if str1 == str2
template streq(char [] str1, char[] str2)
{
   static if (str1.length!=str2.length) const bool streq=false;
   else static if (str1[0]!=str2[0]) const bool streq=false;
   else static if (str1.length==1) const bool streq=true;
   else const bool streq = .streq!(str1[1..str1.length], 
str2[1..str2.length]);
}

---------------------
AESTHETIC: Allow $ as a compile time constant

You can always use .length instead, so it's never really a problem.
Previously reported as a bug (digitalmars.com digitalmars.D.bugs:5977);
could be considered to be a limitation instead.
Jan 17 2006
next sibling parent reply Georg Wrede <georg.wrede nospam.org> writes:
Don Clugston wrote:
 The items in this list mostly fall into the category of limitations 
 rather than bugs; but in each case, the limitations are unintuitive.
 I've listed them in order of decreasing importance.
 Workarounds are also shown.
 
 ---------------------
 MAJOR: Restrictions on static if in templates
 
 Quoting the docs:
 "StaticIfConditions cannot appear at module scope. They can appear in
 class, template, struct, union, or function scope. In function scope,
 the symbols referred to in the AssignExpression can be any that can
 normally be referenced by an expression at that point. Otherwise, the
 only symbols that can be referred to are up one scope level from the
 condition."
 ...
 "It does not introduce a new scope even if { }  are used for
 conditionally compiled statements."
 
 Together, these restrictions mean that a metafunction can't store
 intermediate results, so that complex template code like pragma's regex 
 gets quite ugly and convoluted.
 
 Workaround: invoke the metafunction every time you want to use the 
 result from it. (Sometimes this can result in a drastic increase in
 the number of template instantiations required).
 
 ---------------------
 MINOR: Allow concatenation char[] ~ char
 
 Desired:
   const char [] s = "abcdef" ~ 'g';
 
 Workaround: Ugly. Convert char to char[] by taking slices of a string 
 containing all characters. Only works for char, not for wchar, dchar.
 
   const char [] s = "abcdef" ~ makechar!('g');
 
 /// converts a single char to a char[]
 template makechar(int c)
 {
   const char [] makechar=
 x"000102030405060708090a0b0c0d0e0f                         
 101112131415161718191a1b1c1d1e1f                         
 202122232425262728292a1b2c2d2e2f                         
 303132333435363738393a3b3c3d3e3f                         
 404142434445464748494a4b4c4d4e4f                         
 505152535455565758595a5b5c5d5e5f                         
 606162636465666768696a6b6c6d6e6f                         
 707172737475767778797a7b7c7d7e7f                         
 808182838485868788898a8b8c8d8e8f                         
 909192939495969798999a9b9c9d9e9f                         
 a0a1a2a3a4a5a6a7a8a9aaabacadaeaf                         
 b0b1b2b3b4b5b6b7b8b9babbbcbdbebf                         
 c0c1c2c3c4c5c6c7c8c9cacbcccdcecf                         
 d0d1d2d3d4d5d6d7d8d9dadbdcdddedf                         
 e0e1e2e3e4e5e6e7e8e9eaebecedeeef                         
 f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"[c..c+1];
 }
 
 ---------------------
 AESTHETIC: The . in recursive templates.
 
 template fact(int x)
 {
   static if (x>1)  const int fact = x * .fact!(x-1);
   else const int fact = 1;
 }
 
 The dot is a workaround, only needed because the constant "fact" we're
 setting is in scope.
 Why is it already in the symbol table? The workaround is more complex 
 when the template is not at module scope -- you need to include dot plus 
 fully qualified name. The following example works:
 
 struct outer
 {
     template fact(int x)
     {
       static if (x>1)  const int fact = x * .outer.fact!(x-1);
       else const int fact = 1;
     }
     static assert(fact!(6)==8);
 }
 
 If you leave off the dot before the outer, ie
       static if (x>1)  const int fact = x * outer.fact!(x-1);
 then the error message is:
 
  template fact!(x - 1) is not a member of outer
 
 which is a little weird.
 
 ---------------------
 MINOR: Allow compile time equality comparisions char[] == char[], char[] 
 != char[]
 
 This would be a problem if the workaround was not so easy.
 
 
 // return true if str1 == str2
 template streq(char [] str1, char[] str2)
 {
   static if (str1.length!=str2.length) const bool streq=false;
   else static if (str1[0]!=str2[0]) const bool streq=false;
   else static if (str1.length==1) const bool streq=true;
   else const bool streq = .streq!(str1[1..str1.length], 
 str2[1..str2.length]);
 }
 
 ---------------------
 AESTHETIC: Allow $ as a compile time constant
 
 You can always use .length instead, so it's never really a problem.
 Previously reported as a bug (digitalmars.com digitalmars.D.bugs:5977);
 could be considered to be a limitation instead.
This is drastically different from what I've been (all year) talking about. Still, the way Don puts it, I've a hard time figuring out why _not_ do this like he proposes. Of course, the difference (or should I say "_the_ difference" between me and Don is, he's more Politically Correct, more Socially Adept, etc. (No disrespect to Don.)) I tend to pursue issues I feel intuitively deserve the attention, while Don is Diligent (meaning: by the time he suggests something, there is _no_way_ anybody could kick the suggestion in the knee). --- The message (above), to which I'm responding, is written on the 17th, while right now it is the 20th. Considering the respect Don deserves, even a "I've read it, let's see, we'll be back" response would be more appropiate than just silence. ((((( I must be getting in the Meno Pause Age here, but hey, such affected women don't acknowledge that either! ))))))
Jan 19 2006
next sibling parent Sean Kelly <sean f4.ca> writes:
Georg Wrede wrote:
 
 The message (above), to which I'm responding, is written on the 17th, 
 while right now it is the 20th. Considering the respect Don deserves, 
 even a "I've read it, let's see, we'll be back" response would be more 
 appropiate than just silence.
I've run into most of the problems Don describes and I agree with all of his suggestions. I hadn't replied until now mostly because I generally avoid "me too" posts, but perhaps it woul help in this case :-) Sean
Jan 20 2006
prev sibling parent reply "Walter Bright" <newshound digitalmars.com> writes:
"Georg Wrede" <georg.wrede nospam.org> wrote in message 
news:43D05AF5.7030904 nospam.org...
 The message (above), to which I'm responding, is written on the 17th, 
 while right now it is the 20th. Considering the respect Don deserves, even 
 a "I've read it, let's see, we'll be back" response would be more 
 appropiate than just silence.
On the 17th and 18th I attended a conference, and on the 18th I was giving a presentation. So that consumed all my time. On the evening of the 18th, I left for a brief business trip and just got back. So as for what Don's message deserves, the problems have all been corrected and will go out in the next update.
Jan 21 2006
parent Georg Wrede <georg.wrede nospam.org> writes:
Walter Bright wrote:
 "Georg Wrede" <georg.wrede nospam.org> wrote in message 
 news:43D05AF5.7030904 nospam.org...
 
The message (above), to which I'm responding, is written on the 17th, 
while right now it is the 20th. Considering the respect Don deserves, even 
a "I've read it, let's see, we'll be back" response would be more 
appropiate than just silence.
On the 17th and 18th I attended a conference, and on the 18th I was giving a presentation. So that consumed all my time. On the evening of the 18th, I left for a brief business trip and just got back. So as for what Don's message deserves, the problems have all been corrected and will go out in the next update.
Cool!!!
Jan 22 2006
prev sibling parent Chris Lajoie <ctlajoie___remove___this___ ___gmail.com> writes:
Don Clugston wrote:
 [everything Don said]
signed. most of these seem like relatively minor things but I would personally consider them bugs that should be "fixed". Chris
Jan 20 2006