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.

Any chance that concatenation onto a variable will be supported?

I'd like to write this:

char[] NReps(char[] x, int n)
{
    char[] ret = "";
    for(int i=0; i<n; i++) { ret ~= x; }
    return ret;
}

But that doesn't work.  The recursive version does, though:

char[]  NReps2(char[] x, int n, char[] acc="")
{
    if (n<=0) return acc;
    return NReps2(x, n-1, acc~x);
}

--bb
February 16, 2007
Russell Lewis wrote:
> But here's my question: How do we have a compile-time switch which controls what to compile-time evaluate and what not?

It's not necessary. The context completely determines what to compile-time and what to run-time.
February 16, 2007
Michiel wrote:
> * the syntax for functions to be executed at compile time isn't the
> nice-and-simple D syntax, but the template-syntax. And in another thread
> you yourself have mentioned why that's not optimal. I agree.

I don't think eval!(expression) is an undue burden. It's hard to imagine how any other syntax would look better.
February 16, 2007
Bill Baxter wrote:
> Right.  But if I understand correctly, the same code can get called either at runtime or compile time depending on the situation.

Yes.

> But what if I want the runtime version to print out a message.  Or add to a global counter variable for some simple home-brew profiling stats.  It would be handy then if I could do:
> 
> int square(int x) {
>    version(compiletime) {}else{
>      writefln("trace: square");
>      G_CallsToSquare++;
>    }
>    return (x*x);
> }

I see what you want, but it isn't going to work the way the compiler is built. Runtime interpretation occurs *after* semantic analysis, but versioning happens before. Right now, you're better off having two functions, one a wrapper around the other.

After all, there isn't a version possible for inlining/not inlining, either.

> I think I'm getting at the same kind of thing Andrei is talking about. I don't want to have to limit what I do in the runtime version in order to make it acceptable for compile time.  He's saying I should be able to have two versions of the function, one for compile time and one for run time.  I think that's useful too.  But for simpler cases like the above, it would be nice I think if one could just version-out the bad parts.
> 
> And in this case:
> 
> int calculationIShouldOnlyDoAtCompileTime(int x)
> {
>    // * whatever it is *
> }
> 
> int K = calculationIShouldOnlyDoAtCompileTime(4);
> 
> Whoops!  Silly programmer, looks like I forgot the 'const' on K.  Would be nice if I could get the compiler to remind me when I'm silly like that.  That could be arranged if there were a version(CompileTime).

For compile time evaluation only, make the function instead a template that calls the function.


> For instance, it's not uncommon to make a fixed length vector class using templates.  Vec!(N) kind of thing.  But it would really be nice if the majority of that code could remain even when N is not constant. That means both on the user side and on the implementation side.  I don't know how realistic that is, but I often find myself sitting on the fence trying to decide -- do I make this a compile-time parameter, thereby cutting off all opportunity for runtime creation of a particular instance, or do I make it runtime, thereby cutting my and the compiler's opportunity to make several obvious optimizations.

Templates are supposed to fill that ecological niche.
February 16, 2007
Bill Baxter wrote:
> Yeh, it's not a big deal.  I was more just curious since you recently added it back to DMD.  And since it does affect the /effective/ semantics if you have a very deep recursion that overflows the stack. Or is the stack for compile-time execution is actually on the heap?
> 
> Either way, it might actually be /better/ to have the compile-time implementation have a limited stack so that infinite recursion errors result in stack overflows rather than just the compiler hanging.

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.
February 16, 2007
Bill Baxter wrote:
> This doesn't seem to work either -- should it?

Looks like it should. I'll check it out.
February 16, 2007
Bill Baxter wrote:
> Any chance that concatenation onto a variable will be supported?

It should. I'll figure out what's going wrog, wring, worng, er, wrong.
February 16, 2007
many others asked about explicitly run at compile time, and there is this template solution.

doesn't this again end up in a new type?

I personally do not like the eval!( func() ) syntax.
I think this is a new important feature, worth a new syntax.

How about something like

func!!()
func#()

This new call syntax forces a function to run in the compiler.
February 16, 2007
Frank Benoit (keinfarbton) wrote:
> many others asked about explicitly run at compile time, and there is
> this template solution.
> 
> doesn't this again end up in a new type?
> 
> I personally do not like the eval!( func() ) syntax.
> I think this is a new important feature, worth a new syntax.
> 
> How about something like
> 
> func!!()
> func#()
> 
> This new call syntax forces a function to run in the compiler.


I like eval!(func()) for that.

I keep thinking, though, that some new syntax would sure be nice for mixin(func!(arg)).  It seems that things such as

   mixin(write!("foo %{bar} is %{baz}"));

could potentially get very tiresome.  If I have to write mixin(...) everywhere I'm probably just going to end up going with

   writefn("foo %s is %s",  bar, baz);

I was actually thinking of your func!!().  But eh.  It's not so clear cut with all these possible forms of mixin()

     mixin("char x;");
     mixin(func());
     mixin(tfunc!());
     mixin("char " ~ "x");
     mixin("char " ~ func());
     mixin("char " ~ tfunc!());

... etc.


--bb
February 16, 2007
Bill Baxter wrote:
> Frank Benoit (keinfarbton) wrote:
>> many others asked about explicitly run at compile time, and there is
>> this template solution.
>>
>> doesn't this again end up in a new type?
>>
>> I personally do not like the eval!( func() ) syntax.
>> I think this is a new important feature, worth a new syntax.
>>
>> How about something like
>>
>> func!!()
>> func#()
>>
>> This new call syntax forces a function to run in the compiler.
> 
> 
> I like eval!(func()) for that.
> 
> I keep thinking, though, that some new syntax would sure be nice for mixin(func!(arg)).  It seems that things such as
> 
>    mixin(write!("foo %{bar} is %{baz}"));
> 
> could potentially get very tiresome.

Definitely. That's exactly why dispatch of the same code through compile-time and run-time channels, depending on the argument, must be easy.

Andrei