February 15, 2007
Michiel wrote:
> That's a great feature! A couple of questions, if I may:
> 
> * Can sqrt still call another function?

Yes, as long as that function can also be compile time executed. Recursion works, too.

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

No, yes, array literals only.

> * Why is the second sqrt(10) run at runtime?

Because the compiler cannot tell if it is a reasonable thing to try and execute it at compile time. To force it to happen at compile time:

template eval(A...) { alias A eval; }

writefln("%s", eval!(sqrt(10)));

which works because templates can only take constants as value arguments.

> In theory it's still a
> constant, right?

No.

> Is this something that will work in a later version?

I don't see a motivating reason why, at the moment, given the eval template.
February 15, 2007
Gregor Richards wrote:
> 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 ^^

That's a bug. I'll fix it.
February 15, 2007
Reply to Walter,

> 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.
> 


Hmm, so compile time evaluation is lazy, not greedy? That makes me want a cast(const) to force it in some cases


char[] CTwritef(...)

const char[] message = CTwritef(">>%s:%d foobar", __FILE__, __LINE__+1);
log(message);

vs.

log(cast(const)CTwritef(">>%s:%d foobar", __FILE__, __LINE__+1));

or best of all, why no have it greedy?

log(CTwritef(">>%s:%d foobar", __FILE__, __LINE__+1));


February 15, 2007
BCS wrote:
> Hmm, so compile time evaluation is lazy, not greedy?

Yes.

> That makes me want a cast(const) to force it in some cases

I think the eval() template does that nicely.
February 15, 2007
Walter Bright wrote:
> ... is now in DMD 1.006. For example:
> 

Very nice!

A few questions:
1) You say recursion is allowed -- does it do proper tail recursion?

2) Can't you just ignore 'synchronized' at compile time?

3) Would it be possible to add some sort of a version(CompileTime)? This would make it possible for those who want to be *sure* the function is only used at compile time to simply have it not exist as a runtime call.  It could also be used to make slight modifications to functions that one would like to use as both compile-time and run-time.  For example if you want to have synchronized/try/catch/throw/writefln type things in the runtime version.

--bb
February 15, 2007
Frits van Bommel wrote:

>> * 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.

Well, then there is room for improvement. (Good thing, too. Can you
imagine how bad it would be if perfection had already been achieved? ;))

Anyway, it looks to me like every subtree of the abstract syntax tree could potentially be collapsed by compile time function execution. This would include the mentioned sqrt call. Of course, I don't really know how the D compiler works internally, so I can't be sure in this case.

And I don't see a real reason why structs and at least scope classes couldn't be included. But I don't suppose it's all that easy.

Maybe the perfect compiler would also pre-execute everything up until the first input is needed. And maybe some bits after.

-- 
Michiel
February 15, 2007
Walter Bright wrote:
> Walter Bright wrote:
>> This should obsolete using templates to compute values at compile time.
> 
> For contrast, compare with the C++ proposal:
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1972.pdf

It's kinda long and boring, but it looks like the key differences are

1) The need to tag compile-time functions with a new keyword, "constexpr", though they seem to sell this as an advantage.  "a programmer can state that a function is intended to be used in a constant expression and the compiler can diagnose mistakes." -- page 9.

2) The restriction that a constexpr function can only contain "return" followed by exactly one expression.  No loops for you!  And I hope you like quadruply nested b?x:y expressions!

That's just a proposal, though, right?  Has it been accepted for C++09?   Seems like a hard sell given the limitations and the new keyword.

--bb
February 15, 2007
Michiel wrote:
> Frits van Bommel wrote:
> 
>>> * 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.
> 
> Well, then there is room for improvement. (Good thing, too. Can you
> imagine how bad it would be if perfection had already been achieved? ;))
> 
> Anyway, it looks to me like every subtree of the abstract syntax tree
> could potentially be collapsed by compile time function execution. This
> would include the mentioned sqrt call. Of course, I don't really know
> how the D compiler works internally, so I can't be sure in this case.
> 
> And I don't see a real reason why structs and at least scope classes
> couldn't be included. But I don't suppose it's all that easy.
> 
> Maybe the perfect compiler would also pre-execute everything up until
> the first input is needed. And maybe some bits after.

You do need some way to turn it off though.
For an extreme example, most programs from the demoscene make extensive use of compressed data that is uncompressed as the first step before running.  They would be very unhappy if their language chose to be "helpful" by running the decompression routines at compile-time thus resulting in a 20M executable.

Extreme -- but it does demonstrate there are cases where you want to be sure some expansion happens at runtime.

--bb
February 15, 2007
Bill Baxter wrote:

>> Maybe the perfect compiler would also pre-execute everything up until the first input is needed. And maybe some bits after.
> 
> You do need some way to turn it off though.
> For an extreme example, most programs from the demoscene make extensive
> use of compressed data that is uncompressed as the first step before
> running.  They would be very unhappy if their language chose to be
> "helpful" by running the decompression routines at compile-time thus
> resulting in a 20M executable.
> 
> Extreme -- but it does demonstrate there are cases where you want to be sure some expansion happens at runtime.

Very good point. This could be solved by using some sort of conditional compilation construct on the bits you want to happen at runtime.

-- 
Michiel
February 15, 2007
Walter Bright wrote:
> Michiel wrote:
>> That's a great feature! A couple of questions, if I may:
>>
>> * Can sqrt still call another function?
> 
> Yes, as long as that function can also be compile time executed. Recursion works, too.
> 
>> * Does it still work if classes or structs are involved in any way? What
>> about enums? What about arrays?
> 
> No, yes, array literals only.
> 
>> * Why is the second sqrt(10) run at runtime?
> 
> Because the compiler cannot tell if it is a reasonable thing to try and execute it at compile time. To force it to happen at compile time:
> 
> template eval(A...) { alias A eval; }
> 
> writefln("%s", eval!(sqrt(10)));
> 
> which works because templates can only take constants as value arguments.

The feature of binding expressions to aliases will break eval.

Andrei