February 16, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Walter Bright wrote:
>> janderson wrote:
>>> Walter Bright wrote:
>>>> Right now, the compiler will fail if the compile time execution results in infinite recursion or an infinite loop. I'll have to figure out some way to eventually deal with this.
>>>
>>> Maybe you could allow the user to specify stack size and maximum iteration per loop/recursion function to the compiler as flags (with some defaults).   This way the user can up the size if they really need it.  This would make it a platform thing.  That way a D compiler could still be made for less powerful systems.
>>
>> Whether you tell it to fail at a smaller limit, or it fails by itself at a smaller limit, doesn't make any difference as to whether it runs on a less powerful system or not <g>.
>>
>> The C standard has these "minimum translation limits" for all kinds of things - number of lines, chars in a string, expression nesting level, etc. It's all kind of bogus, hearkening back to primitive compilers that actually used fixed array sizes internally (Brand X, who-shall-not-be-named, was notorious for exceeding internal table limits, much to the delight of Zortech's sales staff). The right way to build a compiler is it either runs out of stack or memory, and that's the only limit.
>>
>> If your system is too primitive to run the compiler, you use a cross compiler running on a more powerful machine.
>>
>> I have thought of just putting a timer in the interpreter - if it runs for more than a minute, assume things have gone terribly awry and quit with a message.
> 
> That could be achieved with a watchdog process without changing the compiler, and it's more flexible.
> 
> I think you just let the compiler go and crunch at it. Since you esentially have partial evaluation anyway, the execution process can be seen as extended to compile time. If you have a non-terminating program, that non-termination can be naturally manifest itself during compilation=partial evaluation.
> 

Completely agree, otherwise it contradicts your "right way to build a compiler" statement except with time as the metric instead of memory. Imagine the frustration of someone who has legitimate code and the compiler always craps out half-way through a looong makefile, or worse only sometimes craps out depending on machine load.

I think the best solution is to list out any compile-time execution with the '-v' switch. That way if someone runs into this, they can throw -v and find out where it's happening.

> 
> Andrei
February 16, 2007
Bill Baxter wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>> Walter Bright wrote:
> 
>> That could be achieved with a watchdog process without changing the compiler, and it's more flexible.
>>
>> I think you just let the compiler go and crunch at it. Since you esentially have partial evaluation anyway, the execution process can be seen as extended to compile time. If you have a non-terminating program, that non-termination can be naturally manifest itself during compilation=partial evaluation.
> 
> It would be nice though, if the compiler could trap sigint or something and spit out an error message about which part of the code it was trying to compile when you killed it.
> 
> Otherwise debugging accidental infinite loops in compile time code becomes...interesting.
> 
> --bb

How about listing any CTFE with -v? That should be more reliable and useful in other ways too.
February 16, 2007
Walter Bright wrote:
> torhu wrote:
>> Walter Bright wrote:
>>> This should obsolete using templates to compute values at compile time.
>>
>> Wonderful feature, but look at this:
>>
>> int square(int x)
>> {
>>    return x * x;
>> }
>>
>> const int foo = square(5);
>>
>> al_id4.d(6): Error: cannot evaluate (square)(5) at compile time
>>
>>
>> I was hoping this would make some C macros easier to replace, without needing template versions for initializing consts.
> 
> Aggh, that's a compiler bug.
> 
> int foo = square(5);
> 
> does work. I knew I'd never get it right the first try :-(

Wait -- int foo = square(5); is supposed to CTFE? If so that'd be awesome.
February 16, 2007
Dave wrote:
> Bill Baxter wrote:
> 
>> Andrei Alexandrescu (See Website For Email) wrote:
>>
>>> Walter Bright wrote:
>>
>>
>>> That could be achieved with a watchdog process without changing the compiler, and it's more flexible.
>>>
>>> I think you just let the compiler go and crunch at it. Since you esentially have partial evaluation anyway, the execution process can be seen as extended to compile time. If you have a non-terminating program, that non-termination can be naturally manifest itself during compilation=partial evaluation.
>>
>>
>> It would be nice though, if the compiler could trap sigint or something and spit out an error message about which part of the code it was trying to compile when you killed it.
>>
>> Otherwise debugging accidental infinite loops in compile time code becomes...interesting.
>>
>> --bb
> 
> 
> How about listing any CTFE with -v? That should be more reliable and useful in other ways too.

On the line, how about a timeout flag for unattended builds? As it is DMD can now fail to error on bad code by just running forever. With template code it would seg-v sooner or later.
February 16, 2007
Walter Bright wrote:
> ... is now in DMD 1.006. For example:
> 
>> -------------------------------------------
>> import std.stdio;
>>
>> real sqrt(real x)
>> {
>>    real root = x / 2;
>>    for (int ntries = 0; ntries < 5; ntries++)
>>    {
>>        if (root * root - x == 0)
>>            break;
>>        root = (root + x / root) / 2;
>>    }
>>    return root;
>> }
>>
>> void main()
>> {
>>    static x = sqrt(10);   // woo-hoo! set to 3.16228 at compile time!
>>    writefln("%s, %s", x, sqrt(10));  // this sqrt(10) runs at run time
>> }
>> ------------------------------------------
> 
> This should obsolete using templates to compute values at compile time.


I didn't read the whole thread, but I just found some replies about how to turn off/on the automatic compile time execution.

I would suggest, that the default behaviour will be "execute as much as possible during compile time", but that there are two keywords (possibly "runtime" and "compiletime") that will indicate what the method is, for example:

runtime float sqrt()
{
   ...
}

That would expand to that the function is _not_ executed during compile
time, even if it would be able to.
On the other hand,

compiletime float sqrt()
{
   ...
}

Will be executed during compile time (as the standard). But as a difference to the regular behaviour, a function declared as "compiletime" that may not be executed during compile time may throw a hint when compiling so that the developer may change it until there's no hint left.

greetings
Nicolai
February 16, 2007
Dave wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>> Walter Bright wrote:
>>> janderson wrote:
>>>> Walter Bright wrote:
>>>>> Right now, the compiler will fail if the compile time execution results in infinite recursion or an infinite loop. I'll have to figure out some way to eventually deal with this.
>>>>
>>>> Maybe you could allow the user to specify stack size and maximum iteration per loop/recursion function to the compiler as flags (with some defaults).   This way the user can up the size if they really need it.  This would make it a platform thing.  That way a D compiler could still be made for less powerful systems.
>>>
>>> Whether you tell it to fail at a smaller limit, or it fails by itself at a smaller limit, doesn't make any difference as to whether it runs on a less powerful system or not <g>.
>>>
>>> The C standard has these "minimum translation limits" for all kinds of things - number of lines, chars in a string, expression nesting level, etc. It's all kind of bogus, hearkening back to primitive compilers that actually used fixed array sizes internally (Brand X, who-shall-not-be-named, was notorious for exceeding internal table limits, much to the delight of Zortech's sales staff). The right way to build a compiler is it either runs out of stack or memory, and that's the only limit.
>>>
>>> If your system is too primitive to run the compiler, you use a cross compiler running on a more powerful machine.
>>>
>>> I have thought of just putting a timer in the interpreter - if it runs for more than a minute, assume things have gone terribly awry and quit with a message.
>>
>> That could be achieved with a watchdog process without changing the compiler, and it's more flexible.
>>
>> I think you just let the compiler go and crunch at it. Since you esentially have partial evaluation anyway, the execution process can be seen as extended to compile time. If you have a non-terminating program, that non-termination can be naturally manifest itself during compilation=partial evaluation.
>>
> 
> Completely agree, otherwise it contradicts your "right way to build a compiler" statement except with time as the metric instead of memory. Imagine the frustration of someone who has legitimate code and the compiler always craps out half-way through a looong makefile, or worse only sometimes craps out depending on machine load.

Yes, memory watching would be great. It is easy to write a script that watches dmd's memory and time consumed, and kills it past some configurable threshold.

> I think the best solution is to list out any compile-time execution with the '-v' switch. That way if someone runs into this, they can throw -v and find out where it's happening.

Sounds great.

Andrei
February 16, 2007
Dave wrote:

>> Aggh, that's a compiler bug.
>>
>> int foo = square(5);
>>
>> does work. I knew I'd never get it right the first try :-(
> 
> Wait -- int foo = square(5); is supposed to CTFE? If so that'd be awesome.

I don't think so. If I'm not mistaken, D would do that at runtime at the moment.

-- 
Michiel
February 16, 2007
Nicolai Waniek wrote:

> I didn't read the whole thread, but I just found some replies about how to turn off/on the automatic compile time execution.
> 
> I would suggest, that the default behaviour will be "execute as much as possible during compile time", but that there are two keywords (possibly "runtime" and "compiletime") that will indicate what the method is, for

I am in total agreement.

-- 
Michiel
February 16, 2007
Michiel wrote:
> Dave wrote:
>>> int foo = square(5);
>>>
>>> does work. I knew I'd never get it right the first try :-(
>> Wait -- int foo = square(5); is supposed to CTFE? If so that'd be awesome.
> 
> I don't think so. If I'm not mistaken, D would do that at runtime at the
> moment.
> 

Not for a global declaration, which must happen at compile time.
February 16, 2007
Michiel wrote:
> Dave wrote:
> 
>>> Aggh, that's a compiler bug.
>>>
>>> int foo = square(5);
>>>
>>> does work. I knew I'd never get it right the first try :-(
>> Wait -- int foo = square(5); is supposed to CTFE? If so that'd be awesome.
> 
> I don't think so. If I'm not mistaken, D would do that at runtime at the
> moment.

It does that at runtime for variables in function-type scope. For global variables (as in the code posted) and IIRC aggregate members it determines initial values at compile time.