Thread overview
template functions, a special case of constant folding?
Mar 23, 2006
Hasan Aljudy
Mar 23, 2006
Hasan Aljudy
Mar 24, 2006
Deewiant
Mar 23, 2006
Derek Parnell
Mar 24, 2006
James Dunne
Mar 24, 2006
Hasan Aljudy
Mar 25, 2006
Kevin Bealer
Mar 24, 2006
Knud Sørensen
March 23, 2006
Given the following expression:
#x = 10 * 5 + y;
the compiler will compute 10 * 5 at compile-time and convert the expression into
#x = 50 + y;

I think that's called constant-folding, am I right?

Why can't this be extended such that for the following function:
# int add( int x, int y ) { return x + y; }

if it's called with constant arguments:
# x = add( 10, 3 );

the compiler shall do the computation at compile time and convert it to:
# x = 13;
is there a particular reason for not doing that?

What I'm trying to say is, why do we need templates to do compile-time computation of square roots? (as shown on http://www.digitalmars.com/d/templates-revisited.html)

Why not, instead of calling the templated sqrt
#    x = sqrt!(2);
you just call the regular sqrt
#    x = sqrt(2);
and the compiler, if smart enough, should do the computation at compile time?

If it's too hard to make the compiler smart enough, then maybe we can add a keyword to hint to the compiler that if all arguments to this function are constants then it can be "folded"!
After all, that's essentially what the "template" keyword is doing! (kinda, not really though, I know).

# fold int add( int x, int y ) { return x + y; }
vs.
# template add( int x, int y ) { const add = x + y; }

The "fold" version of the function can be reused for non-constant arguments. Where as the templated version can't. (although I'm not entirely sure about that).





March 23, 2006
Sorry, should've gone to the D section!!

Hasan Aljudy wrote:
> Given the following expression:
> #x = 10 * 5 + y;
> the compiler will compute 10 * 5 at compile-time and convert the expression into
> #x = 50 + y;
> 
> I think that's called constant-folding, am I right?
> 
> Why can't this be extended such that for the following function:
> # int add( int x, int y ) { return x + y; }
> 
> if it's called with constant arguments:
> # x = add( 10, 3 );
> 
> the compiler shall do the computation at compile time and convert it to:
> # x = 13;
> is there a particular reason for not doing that?
> 
> What I'm trying to say is, why do we need templates to do compile-time computation of square roots? (as shown on http://www.digitalmars.com/d/templates-revisited.html)
> 
> Why not, instead of calling the templated sqrt
> #    x = sqrt!(2);
> you just call the regular sqrt
> #    x = sqrt(2);
> and the compiler, if smart enough, should do the computation at compile time?
> 
> If it's too hard to make the compiler smart enough, then maybe we can add a keyword to hint to the compiler that if all arguments to this function are constants then it can be "folded"!
> After all, that's essentially what the "template" keyword is doing! (kinda, not really though, I know).
> 
> # fold int add( int x, int y ) { return x + y; }
> vs.
> # template add( int x, int y ) { const add = x + y; }
> 
> The "fold" version of the function can be reused for non-constant arguments. Where as the templated version can't. (although I'm not entirely sure about that).
> 
> 
> 
> 
> 
March 23, 2006
On Thu, 23 Mar 2006 16:34:07 -0700, Hasan Aljudy wrote:

> Given the following expression:
> #x = 10 * 5 + y;
> the compiler will compute 10 * 5 at compile-time and convert the
> expression into
> #x = 50 + y;
> 
> I think that's called constant-folding, am I right?
> 
> Why can't this be extended such that for the following function: # int add( int x, int y ) { return x + y; }
> 
> if it's called with constant arguments:
> # x = add( 10, 3 );
> 

You can almost do this with mixins, except that mixins only allow one to mixin a complete statement and not just an expression. What would be useful is to allow mixins (or some other similar thing) to generate expressions at compile time and not just statements. Something like ...


 template add(b,c)
 {
    b + c;
 }

 int main()
 {
   int q;
   q = mixin add!(10,3);
   return q;
 }

Which would generate

 int main()
 {
   int q;
   q = 10 + 3;
   return q;
 }

Which the compiler would constant-fold as normal.

But this is starting to look too much like text macros which Walter is very concerned not to have.

-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
"Down with mediocracy!"
24/03/2006 10:51:16 AM
March 24, 2006
Derek Parnell wrote:
> On Thu, 23 Mar 2006 16:34:07 -0700, Hasan Aljudy wrote:
> 
> 
>>Given the following expression:
>>#x = 10 * 5 + y;
>>the compiler will compute 10 * 5 at compile-time and convert the expression into
>>#x = 50 + y;
>>
>>I think that's called constant-folding, am I right?
>>
>>Why can't this be extended such that for the following function:
>># int add( int x, int y ) { return x + y; }
>>
>>if it's called with constant arguments:
>># x = add( 10, 3 );
>>
> 
> 
> You can almost do this with mixins, except that mixins only allow one to
> mixin a complete statement and not just an expression. What would be useful
> is to allow mixins (or some other similar thing) to generate expressions at
> compile time and not just statements. Something like ...
> 
>   template add(b,c)
>  {
>     b + c;
>  }
> 
>  int main()
>  {
>    int q;
>    q = mixin add!(10,3);
>    return q;
>  }
> 
> Which would generate 
> 
>  int main()
>  {
>    int q;
>    q = 10 + 3;
>    return q;
>  }
> 
> Which the compiler would constant-fold as normal.
> 
> But this is starting to look too much like text macros which Walter is very
> concerned not to have.
> 

Why not reuse alias?  Aliased expressions.

-- 
Regards,
James Dunne
March 24, 2006
Derek Parnell wrote:
> On Thu, 23 Mar 2006 16:34:07 -0700, Hasan Aljudy wrote:
> 
> 
>>Given the following expression:
>>#x = 10 * 5 + y;
>>the compiler will compute 10 * 5 at compile-time and convert the expression into
>>#x = 50 + y;
>>
>>I think that's called constant-folding, am I right?
>>
>>Why can't this be extended such that for the following function:
>># int add( int x, int y ) { return x + y; }
>>
>>if it's called with constant arguments:
>># x = add( 10, 3 );
>>
> 
> 
> You can almost do this with mixins, except that mixins only allow one to
> mixin a complete statement and not just an expression. What would be useful
> is to allow mixins (or some other similar thing) to generate expressions at
> compile time and not just statements. Something like ...
> 
>   template add(b,c)
>  {
>     b + c;
>  }
> 
>  int main()
>  {
>    int q;
>    q = mixin add!(10,3);
>    return q;
>  }
> 
> Which would generate 
> 
>  int main()
>  {
>    int q;
>    q = 10 + 3;
>    return q;
>  }
> 
> Which the compiler would constant-fold as normal.
> 
> But this is starting to look too much like text macros which Walter is very
> concerned not to have.
> 

but you're still using templates. which completely defies my point!
March 24, 2006
Hasan Aljudy wrote:
> Derek Parnell wrote:
>> On Thu, 23 Mar 2006 16:34:07 -0700, Hasan Aljudy wrote:
>>
>>
>>> Given the following expression:
>>> #x = 10 * 5 + y;
>>> the compiler will compute 10 * 5 at compile-time and convert the
>>> expression into
>>> #x = 50 + y;
>>>
>>> I think that's called constant-folding, am I right?
>>>
>>> Why can't this be extended such that for the following function: # int add( int x, int y ) { return x + y; }
>>>
>>> if it's called with constant arguments:
>>> # x = add( 10, 3 );
>>>
>>
>>
>> You can almost do this with mixins, except that mixins only allow one to
>> mixin a complete statement and not just an expression. What would be
>> useful
>> is to allow mixins (or some other similar thing) to generate
>> expressions at
>> compile time and not just statements. Something like ...
>>
>> 
>>  template add(b,c)
>>  {
>>     b + c;
>>  }
>>
>>  int main()
>>  {
>>    int q;
>>    q = mixin add!(10,3);
>>    return q;
>>  }
>>
>> Which would generate
>>  int main()
>>  {
>>    int q;
>>    q = 10 + 3;
>>    return q;
>>  }
>>
>> Which the compiler would constant-fold as normal.
>>
>> But this is starting to look too much like text macros which Walter is
>> very
>> concerned not to have.
>>
> 
> but you're still using templates. which completely defies my point!

Doing this kind of compiler optimization is very expensive (adds compiling time & optimizer complexity and thus more bugs). If you already know that the function should be folded / inlined when you're writing the code, it's a natural way to explicitly say this with templates. I think the compiler already does some tricks when -inline is used. I think new M$ compilers convert stuff like this:

 int a = 5, b = 2;
 for (int i=0; i<3; i++) a *= b;
 int get(int c) { return c+2; }
 a = b = get(a);

into:

 int a = 42, b = 42;

but IMHO it's a sign of a bad coder not to optimize code on the higher levels. It's extremely simple to "hint" to compiler by using templates and lift the burden of implementation to the metaprogramming engine.

-- 
Jari-Matti
March 24, 2006
Hasan Aljudy wrote:
>> If it's too hard to make the compiler smart enough, then maybe we can
>> add a keyword to hint to the compiler that if all arguments to this
>> function are constants then it can be "folded"!
>> After all, that's essentially what the "template" keyword is doing!
>> (kinda, not really though, I know).
>>
>> # fold int add( int x, int y ) { return x + y; }
>> vs.
>> # template add( int x, int y ) { const add = x + y; }
>>
>> The "fold" version of the function can be reused for non-constant arguments. Where as the templated version can't. (although I'm not entirely sure about that).
>>

I'd use something like this syntax, borrowed from C++:

int add(int x, int y) const { return x + y; }

The key here being "const". The function has no side effects, and given the same arguments always returns the same answer. This construct is one of the few I miss from C++, although what I'm talking about might be a bit different - I can't remember, it's been a while since I've done a lot in C++.

This would require the following demands of const functions - they cannot:
	- contain static variables,
	- call non-const functions,
	- refer to non-const variables defined outside their own scope.

And probably something else, too, that I forgot or couldn't think of.

I'm not sure how pointers would fit into the above, though. Should const functions be able to use pointers at all? Only class pointers (which aren't, syntax-wise, pointers per se)? How does it work in C++?

Const functions should basically fit the bill for what you're asking for, although it requires some work from the compiler as well, since it has to check whether you're really right about the constness - or "foldability" as you might call it - by enforcing the above criteria.
March 24, 2006
What if the compiler automatic inlines functions with constant arguments.

Then the optimiser could do some real work on it !

Just a trough.

Knud

On Thu, 23 Mar 2006 16:34:07 -0700, Hasan Aljudy wrote:

> Given the following expression:
> #x = 10 * 5 + y;
> the compiler will compute 10 * 5 at compile-time and convert the
> expression into
> #x = 50 + y;
> 
> I think that's called constant-folding, am I right?
> 
> Why can't this be extended such that for the following function: # int add( int x, int y ) { return x + y; }
> 
> if it's called with constant arguments:
> # x = add( 10, 3 );
> 
> the compiler shall do the computation at compile time and convert it to:
> # x = 13;
> is there a particular reason for not doing that?
> 
> What I'm trying to say is, why do we need templates to do compile-time computation of square roots? (as shown on http://www.digitalmars.com/d/templates-revisited.html)
> 
> Why not, instead of calling the templated sqrt
> #    x = sqrt!(2);
> you just call the regular sqrt
> #    x = sqrt(2);
> and the compiler, if smart enough, should do the computation at compile
> time?
> 
> If it's too hard to make the compiler smart enough, then maybe we can
> add a keyword to hint to the compiler that if all arguments to this
> function are constants then it can be "folded"!
> After all, that's essentially what the "template" keyword is doing!
> (kinda, not really though, I know).
> 
> # fold int add( int x, int y ) { return x + y; }
> vs.
> # template add( int x, int y ) { const add = x + y; }
> 
> The "fold" version of the function can be reused for non-constant arguments. Where as the templated version can't. (although I'm not entirely sure about that).

March 25, 2006
In article <e00jv5$19h2$1@digitaldaemon.com>, =?ISO-8859-1?Q?Jari-Matti_M=E4kel=E4?= says...
>
>Hasan Aljudy wrote:
>> Derek Parnell wrote:
>>> On Thu, 23 Mar 2006 16:34:07 -0700, Hasan Aljudy wrote:
>>>
>>>
>>>> Given the following expression:
>>>> #x = 10 * 5 + y;
>>>> the compiler will compute 10 * 5 at compile-time and convert the
>>>> expression into
>>>> #x = 50 + y;
>>>>
>>>> I think that's called constant-folding, am I right?
>>>>
>>>> Why can't this be extended such that for the following function: # int add( int x, int y ) { return x + y; }
>>>>
>>>> if it's called with constant arguments:
>>>> # x = add( 10, 3 );
>>>>
>>>
>>>
>>> You can almost do this with mixins, except that mixins only allow one to
>>> mixin a complete statement and not just an expression. What would be
>>> useful
>>> is to allow mixins (or some other similar thing) to generate
>>> expressions at
>>> compile time and not just statements. Something like ...
>>>
>>> 
>>>  template add(b,c)
>>>  {
>>>     b + c;
>>>  }
>>>
>>>  int main()
>>>  {
>>>    int q;
>>>    q = mixin add!(10,3);
>>>    return q;
>>>  }
>>>
>>> Which would generate
>>>  int main()
>>>  {
>>>    int q;
>>>    q = 10 + 3;
>>>    return q;
>>>  }
>>>
>>> Which the compiler would constant-fold as normal.
>>>
>>> But this is starting to look too much like text macros which Walter is
>>> very
>>> concerned not to have.
>>>
>> 
>> but you're still using templates. which completely defies my point!
>
>Doing this kind of compiler optimization is very expensive (adds compiling time & optimizer complexity and thus more bugs). If you already know that the function should be folded / inlined when you're writing the code, it's a natural way to explicitly say this with templates. I think the compiler already does some tricks when -inline is used. I think new M$ compilers convert stuff like this:
>
> int a = 5, b = 2;
> for (int i=0; i<3; i++) a *= b;
> int get(int c) { return c+2; }
> a = b = get(a);
>
>into:
>
> int a = 42, b = 42;
>
>but IMHO it's a sign of a bad coder not to optimize code on the higher levels. It's extremely simple to "hint" to compiler by using templates and lift the burden of implementation to the metaprogramming engine.
>
>-- 
>Jari-Matti

An idiom that I find helpful is static variables.

: int[] BuildLookupTable(...)
: {
:     // computes some complex table or
:     // other data set.
: }
:
: int do_lookup(int i)
: {
:     static int[] s = BuildLookupTable(...);
:     return s[i];
: }

The static int[] gets computed once and stored the first time the code runs, after this the compiler just checks that it is assigned.  I use this in C++.

I'm not sure if this works in D, if not you can still do this:

: static int[] s;
: if (s.length == 0) {
:    s = BuildLookupTable();
: }

Sometimes a data structure computation is complex and has a lot of data, but the code to compute it is compact.  This lets you build that code on demand at the point of use, and only if the program needs it.

Kevin