October 26, 2005
I really think the docs for "static if" don't do it justice. Since I'm new to D templates, I've been trying to come up with a more interesting example than the one in the docs. Here's my first attempt. This program prints a nicely-formatted list of the first 30 Fibonnacci numbers _at compile time_.
Note that except for the clunky 'inttostr' template (which is a general utility template, could be quite useful in other contexts), it's not much longer than a straightforward implementation in a functional programming language.

Enjoy!

-----------------------------
template inttostr(int n)
{
   template digittostr(int n)
   {
	  static if (n==0) const char [] s="0";
	  else static if (n==1) const char [] s="1";
	  else static if (n==2) const char [] s="2";
	  else static if (n==3) const char [] s="3";
	  else static if (n==4) const char [] s="4";
	  else static if (n==5) const char [] s="5";
	  else static if (n==6) const char [] s="6";
	  else static if (n==7) const char [] s="7";
	  else static if (n==8) const char [] s="8";
	  else const char [] s="9";
   }
   static if (n<0) const char [] s = "-" ~ inttostr!(-n).s;
   else static if (n<10) const char [] s = digittostr!(n).s;
   else const char [] s = inttostr!(n/10).s ~ digittostr!(n%10).s;
}

template ordinal(int n)
{
  static if (n==1) const char [] ordinal = inttostr!(n).s ~"st";
  else static if (n==2) const char [] ordinal = inttostr!(n).s ~"nd";
  else static if (n==3) const char [] ordinal = inttostr!(n).s ~"rd";
  else const char [] ordinal = inttostr!(n).s ~"th";
}

template fib(int n)
{
    static if (n==0)      const int f=0;
    else static if (n==1) const int f=1;
    else                  const int f = fib!(n-1).f + fib!(n-2).f;
    static if (n>0) {
       pragma(msg, "The " ~ ordinal!(n).ordinal ~
          " Fibonnacci number is "~ inttostr!(fib!(n-1).f).s);
    }
}

int main()
{
   return fib!(30).f;
   ButItWontActuallyCompile;
}
October 26, 2005
Here's an improved version, which generates all Fibonnacci numbers which are small enough to fit in the given integral type. Try changing the last line to short, uint, ulong, etc.
This is something that would be *extremely* hard to do in C++.
I just wish I could improve the digittostr function.

Tested on DMD-Windows 0.136 and 0.137.
-------------------
// Works for any integral type.
template inttostr(Type, Type n)
{
   template digittostr(int n)
   {
      static if (n==0) const char [] s="0";
      else static if (n==1) const char [] s="1";
      else static if (n==2) const char [] s="2";
      else static if (n==3) const char [] s="3";
      else static if (n==4) const char [] s="4";
      else static if (n==5) const char [] s="5";
      else static if (n==6) const char [] s="6";
      else static if (n==7) const char [] s="7";
      else static if (n==8) const char [] s="8";
      else const char [] s="9";
   }
   static if (Type.min<0 && n<0) const char [] s = "-" ~ inttostr!(-n).s;
   else static if (n<10) const char [] s = digittostr!(n).s;
   else const char [] s = inttostr!(Type, n/10).s ~ digittostr!(n%10).s;
}

template ordinal(int n)
{
  static if (n%10==1 && n!=11) const char [] ordinal = inttostr!(int, n).s ~"st";
  else static if (n%10==2 && n!=12) const char [] ordinal = inttostr!(int, n).s ~"nd";
  else static if (n%10==3 && n!=13) const char [] ordinal = inttostr!(int, n).s ~"rd";
  else const char [] ordinal = inttostr!(int, n).s ~"th";
}

// Calculate the nth Fibonnacci number
template fib(Type, int n)
{
    static if (n==1)      const Type f=0;
    else static if (n==2) const Type f=1;
    else                  const Type f = fib!(Type, n-1).f + fib!(Type, n-2).f;
}

template showallfibs(Type)
{
	template showfibs(Type, int n)
	{
	   pragma(msg, "The " ~ ordinal!(n).ordinal ~
		  " Fibonnacci number is "~ inttostr!(Type, fib!(Type, n).f).s);
	   static if (fib!(Type, n).f < Type.max/2) {
		   const int show = showfibs!(Type,n+1).show;
	   } else {
		 const int show = 0;
		 pragma(msg, "The " ~ ordinal!(n+1).ordinal ~
		  " Fibonnacci number is greater than " ~ inttostr!(Type, Type.max).s);
	   }
	}
	const int notfinished = showfibs!(Type, 1).show;
}

static assert(showallfibs!(long).notfinished);
October 26, 2005
In article <djn8dp$93g$1@digitaldaemon.com>, Don Clugston says...
>
>I really think the docs for "static if" don't do it justice. Since I'm new to D templates, I've been trying to come up with a more interesting example than the one in the docs. Here's my first attempt. This program prints a nicely-formatted list of the first 30 Fibonnacci numbers _at compile time_.

Very cool.  I hadn't thought to use pragma(msg) in that way :-)  Nor had I realized that the concatenate operator worked on const declarations.  This is probably the most template-oriented thing I've done in D so far:

http://svn.dsource.org/projects/ares/trunk/src/ares/std/atomic.d

Not as fancy, but it's far more compact and readable than it would have been in C++ (note that the unsigned versions don't work because of a compiler bug).


Sean


October 27, 2005
Sean Kelly wrote:
> In article <djn8dp$93g$1@digitaldaemon.com>, Don Clugston says...
> 
>>I really think the docs for "static if" don't do it justice. Since I'm new to D templates, I've been trying to come up with a more interesting example than the one in the docs. Here's my first attempt. This program prints a nicely-formatted list of the first 30 Fibonnacci numbers _at compile time_.
> 
> 
> Very cool.  I hadn't thought to use pragma(msg) in that way :-)  Nor had I
> realized that the concatenate operator worked on const declarations.

It was pure speculation on my part. I did not expect either of those things to work. I haven't yet worked out what a 'literal' is in D, but it is much more generous than C++. For example, casts are permitted.

  This is
> probably the most template-oriented thing I've done in D so far:
> 
> http://svn.dsource.org/projects/ares/trunk/src/ares/std/atomic.d
> 
> Not as fancy, but it's far more compact and readable than it would have been in
> C++ (note that the unsigned versions don't work because of a compiler bug).

Nice. I haven't used the 'is' operator yet, I think it has enormous potential too. And now we have 'auto' typing...

I've also made a template that calculates pi at compile time by summing a power series. I have hopes that I can make it work to arbitrary precision (it only does reals right now).

Seriously, this compiler is *far* more advanced than the programming techniques we've developed to use it. Now that we know that a compile-time itoa() is possible, and even a basic compile-time printf, I can imagine a whole compile-time library.
October 27, 2005
Don Clugston wrote:
> I really think the docs for "static if" don't do it justice. Since I'm new to D templates, I've been trying to come up with a more interesting example than the one in the docs. Here's my first attempt. This program prints a nicely-formatted list of the first 30 Fibonnacci numbers _at compile time_.
> Note that except for the clunky 'inttostr' template (which is a general utility template, could be quite useful in other contexts), it's not much longer than a straightforward implementation in a functional programming language.
> 
> Enjoy!
> 


really nice work. And when that promotion bug is fixed so things can be writen this way:

template inttostr(int n)
{
   static if (n<0) const char [] inttostr = "-" ~ .inttostr!(-n);
   else static if (n<10) const char [] inttostr = digittostr!(n);
   else const char [] inttostr  = .inttostr!(n/10) ~ digittostr!(n%10);
}

it will be even nicer and easier!
October 27, 2005
Ivan Senji wrote:
> Don Clugston wrote:
> 
>> I really think the docs for "static if" don't do it justice. Since I'm new to D templates, I've been trying to come up with a more interesting example than the one in the docs. Here's my first attempt. This program prints a nicely-formatted list of the first 30 Fibonnacci numbers _at compile time_.
>> Note that except for the clunky 'inttostr' template (which is a general utility template, could be quite useful in other contexts), it's not much longer than a straightforward implementation in a functional programming language.
>>
>> Enjoy!
>>
> 
> 
> really nice work. And when that promotion bug is fixed so things can be writen this way:
> 
> template inttostr(int n)
> {
>    static if (n<0) const char [] inttostr = "-" ~ .inttostr!(-n);
>    else static if (n<10) const char [] inttostr = digittostr!(n);
>    else const char [] inttostr  = .inttostr!(n/10) ~ digittostr!(n%10);
> }
> 
> it will be even nicer and easier!

Indeed. Even better would be if a constant index of an array of constants, was a literal.
Then digittostr would just be

template digittostr(int n) {
  const char [] digittostr="0123456789"[n];
}

at which point it becomes a genuine functional programming language, because you can manipulate lists. (Right now I've shown you can create an arbitrary list, but AFAIK you can't peek inside it).
But maybe there's some syntax it will accept right now.

Walter's created a monster. Who knows what it can do!
October 27, 2005
Don Clugston wrote:
> Indeed. Even better would be if a constant index of an array of constants, was a literal.
> Then digittostr would just be
> 
> template digittostr(int n) {
>   const char [] digittostr="0123456789"[n];
> }
> 

I would expect this to work instead of getting the odd "non-constant expression "0123456789"[5]" error.

But this works :)

template digittostr(int n)
{
  const char[] digittostr;
  static this()
  {
    digittostr = "0123456789"[n..n+1];
  }
}

But unfortunately this way we can't have implicit promotion.


> at which point it becomes a genuine functional programming language, because you can manipulate lists. (Right now I've shown you can create an arbitrary list, but AFAIK you can't peek inside it).
> But maybe there's some syntax it will accept right now.
> 
> Walter's created a monster. Who knows what it can do!

Indeed!
October 27, 2005
Ivan Senji wrote:
> 
> But this works :)
> 

Correction: it works in
  writefln(digittostr!(0).digittostr);

but not at compile time with
  pragma(msg,digittostr!(0).digittostr);

Strange. What does "string expected for message, not 'digittostr'"
mean anyway??

> template digittostr(int n)
> {
>   const char[] digittostr;
>   static this()
>   {
>     digittostr = "0123456789"[n..n+1];
>   }
> }
> 
> But unfortunately this way we can't have implicit promotion.
October 27, 2005
Ivan Senji wrote:
> Ivan Senji wrote:
> 
>>
>> But this works :)
>>
> 
> Correction: it works in
>   writefln(digittostr!(0).digittostr);
> 
> but not at compile time with
>   pragma(msg,digittostr!(0).digittostr);
> 
> Strange. What does "string expected for message, not 'digittostr'"
> mean anyway??

It means it didn't evaluate it at compile time.

We're so close!

I've also tried this way:

   const char q[][] = ["0", "1", "2", "3","4","5","6","7","8","9"];
   const char[] digittostr = q[n];

but it gives the string as q[3], not "3".

It seems that [] is never evaluated at compile time, but it's fascinating that ~ is.
October 27, 2005
Don Clugston wrote:
> Ivan Senji wrote:
>> Strange. What does "string expected for message, not 'digittostr'"
>> mean anyway??
> 
> 
> It means it didn't evaluate it at compile time.
> 

Yes, i figured out this was the problem.

> We're so close!
> 

I hope so.

> I've also tried this way:
> 
>    const char q[][] = ["0", "1", "2", "3","4","5","6","7","8","9"];
>    const char[] digittostr = q[n];
> 
> but it gives the string as q[3], not "3".
> 
> It seems that [] is never evaluated at compile time, but it's fascinating that ~ is.

Yes it is fascinating, i hope this is a bug and not by spec.
Maybe to solve this problem a little Walter-intervention is needed?
« First   ‹ Prev
1 2 3 4
Top | Discussion index | About this forum | D home