February 15, 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.

Hmm... infinite loops are suddenly _really_ slow to compile ;) :
-----
// Slightly modified from example
import std.stdio;

real test(real x)
{
    real root = x / 2;
    for (int ntries = 0; ntries < 5 || true; ntries++) {
        root = (root + x / root) / 2;
    }
    return root;
}

void main()
{
   static x = test(10);
}
-----
(Also, this seems to consume huge amounts of memory)

And error checking could be improved as well: removing the parameter from the call in above code gives
---
test.d(15): function test.test (real) does not match parameter types ()
test.d(15): Error: expected 1 arguments, not 0
dmd: interpret.c:96: Expression* FuncDeclaration::interpret(Expressions*): Assertion `parameters && parameters->dim == dim' failed.
Aborted (core dumped)
---
It tells you what's wrong, but still trips an assert that seems to be about the same error. However:
-----
real test()
{
    return 0.0;
}

void main()
{
   static x = test();
}
-----
Gives:
---
dmd: interpret.c:96: Expression* FuncDeclaration::interpret(Expressions*): Assertion `parameters && parameters->dim == dim' failed.
Aborted (core dumped)
---
(the same assert is tripped)

So I don't know, maybe it's a different bug entirely. Or it tripped the other clause of the assert. I don't feel like inspecting interpret.c to find out what exactly the assert is checking and why it's false...
February 15, 2007
Indeed very nice! :)
February 15, 2007
Ary Manzana wrote:
> BCS escribió:
> 
>> Ary Manzana wrote:
>>
>>> A question: is there anyway the compiler can tell the user if a certain function can be executed at compile time? Those six rules may be hard to memorize and while coding sensitive code it would be great to ask the compiler "Is the function I'm writing can be executed at compile time?". Otherwise it's just a guess.
>>
>>
>> int[foo()] should do it, I think, or temp!(foo()).
>>
>> Both hack, but...
> 
> 
> It would be nice to have something like this in phobos:
> 
> -------------------------------------------------
> import ... ?
> 
> int square(int i) { return i * i; }
> 
> static assert (isCompileTimeExecution(square());
> -------------------------------------------------
> 
> so that if the function is changed you can still assert that or know that you've lost it.

I'd go with an is expression

is(square(int) : const)

sort of in line with the function/etc. stuff.
February 15, 2007
Walter Bright wrote:
> Ary Manzana wrote:
> 
>> A question: is there anyway the compiler can tell the user if a certain function can be executed at compile time? Those six rules may be hard to memorize and while coding sensitive code it would be great to ask the compiler "Is the function I'm writing can be executed at compile time?". Otherwise it's just a guess.
> 
> 
> The way to tell is it gives you an error if you try to execute it at compile time and it cannot be.
> 
> Don't bother trying to memorize the rules, if you follow instead the rule "imagine regular compile time constant folding and extend it to functions" and you'll be about 99% correct.

I think the issue is where compile time and runtime are both allowed, but makes a *BIG* difference in performance.
February 15, 2007
Michiel wrote:
> That's a great feature! A couple of questions, if I may:
> 
> * Can sqrt still call another function?

According to the documentation in the zip, yes. But only functions which can themselves be executed at compile time, of course.

> * Does it still work if classes or structs are involved in any way? What
> about enums? What about arrays?

Classes and structs seem to be disallowed.
Array and string literals can be used as parameters, as long as all members would also be valid parameters by themselves. The body may not use non-const arrays.
Enums aren't mentioned, but either they qualify as integers (meaning they can be passes as parameters) or not. Either way, they're not disallowed in the body so they should be usable there.

> * Why is the second sqrt(10) run at runtime? In theory it's still a
> constant, right? Is this something that will work in a later version?

From the spec:
"""
In order to be executed at compile time, the function must appear in a context where it must be so executed, for example:

    * initialization of a static variable
    * dimension of a static array
    * argument for a template value parameter
"""

So this is only done if it's used in a context where only compile-time constants are allowed.
February 15, 2007
I see that I can't do this:

char[] someCompileTimeFunction()
{
    return "writefln(\"Wowza!\");";
}

int main()
{
    mixin(someCompileTimeFunction());
    return 0;
}


Any chance of compile-time code generation via this mechanism? Or are they simply handled in different, incompatible steps of compilation?

 - Gregor Richards

PS: Yes, I realize this is a terrible idea ^^
February 15, 2007
Ary Manzana wrote:
> 
> It would be nice to have something like this in phobos:

Just a note (has nothing to do with the topic): IMHO, phobos and tango
should be merged somehow, I don't like the idea of having two standard
libraries.
Hopefully, there's someone recognizing this ;)
February 15, 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.

Awesome!!!!
Can't wait to try and play with it!!
(downloading at ~ 11 KB/s)
February 15, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> There is a need for a couple of ancillary features. Most importantly, a constant must be distinguishable from a variable. Consider the example of regex from our correspondence:
> 
> bool b = regexmatch(a, "\n$");
> 
> vs.
> 
> char[] pattern = argv[1];
> bool b = regexmatch(a, pattern);
> 
> You'd want to dispatch regexmatch differently: the first match should be passed to compile-time code that at the end of the day yields:
> 
> bool b = (a[$-1] == '\n');
> 
> while the second should invoke the full-general dynamic pattern matching algorithm since a dynamic pattern is used.

I think that can be done with an improvement to the existing compile time regex library.
February 15, 2007
BCS wrote:
> I think the issue is where compile time and runtime are both allowed, but makes a *BIG* difference in performance.

Right, which is why compile time execution is only done in contexts where it would otherwise error, such as in initialization of global constants.