February 15, 2007
Bill Baxter wrote:
> 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!

3) The C++ feature is applicable to user-defined types.

Andrei
February 15, 2007
Walter Bright wrote:
> 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.

The answer is correct, but does not address the issue I raised.

A simple question is: what is the signature of regexmatch? A
runtime-only version is:

bool regexmatch_1(char[] input, char[] pattern);

A compile-time-only version is:

bool regexmatch_2(pattern : char[])(char[] input);

Notice how the two cannot be called the same way. So the burden is on
the user to specify different syntaxes for the two cases:

bool b1 = regexmatch_1(a, ".* = .*"); // forced runtime
bool b2 = regexmatch_2!(".* = .*")(a); // forced compile-time

Notice that b2 is NOT computed at compile time!!! This is because "a" is
a regular variable. It's just that the code for computing b2 is
radically different from the code for computing b1 because the former
uses static knowledge of the pattern.

The problem is that what's really needed is this:

bool b = regexmatch(string, pattern);

and have regexmatch dispatch to regexmatch_1 if pattern is a variable,
or to regexmatch_2 if pattern is a compile-time constant.

Do you feel me?

What we need is allow a means to overload a function with a template, in
a way that ensures unified invocation syntax, e.g.:

bool regexmatch(char[] str, char[] pat); // 1
bool regexmatch(char[] pat)(char[] str, pat); // 2
bool regexmatch(char[] pat, char[] str)(str, pat); // 3

void main(int argc, char[][] argv)
{
  regexmatch(argv[0], argv[1]); // goes to (1)
  regexmatch(argv[0], ".+"); // goes to (2)
  regexmatch("yah", ".+"); // goes to (3)
}

Notice how the invocation syntax is identical --- an essential artifact.


Andrei
February 15, 2007
Michiel wrote:
> Very good point. This could be solved by using some sort of conditional
> compilation construct on the bits you want to happen at runtime.

It's the other way around. Functions are always executed at runtime, unless they are in a context where a compile-time constant is *required*, such as for global variable initialization or template value arguments.
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

Huh, and Bjarne co-authored that proposal.  I wonder what the reason is for all the restrictions.


Sean
February 15, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> A simple question is: what is the signature of regexmatch? A
> runtime-only version is:
> 
> bool regexmatch_1(char[] input, char[] pattern);
> 
> A compile-time-only version is:
> 
> bool regexmatch_2(pattern : char[])(char[] input);
> 
> Notice how the two cannot be called the same way. So the burden is on
> the user to specify different syntaxes for the two cases:
> 
> bool b1 = regexmatch_1(a, ".* = .*"); // forced runtime
> bool b2 = regexmatch_2!(".* = .*")(a); // forced compile-time
> 
> Notice that b2 is NOT computed at compile time!!! This is because "a" is
> a regular variable. It's just that the code for computing b2 is
> radically different from the code for computing b1 because the former
> uses static knowledge of the pattern.
> 
> The problem is that what's really needed is this:
> 
> bool b = regexmatch(string, pattern);
> 
> and have regexmatch dispatch to regexmatch_1 if pattern is a variable,
> or to regexmatch_2 if pattern is a compile-time constant.
> 
> Do you feel me?

No, but I understand your point.

> What we need is allow a means to overload a function with a template, in
> a way that ensures unified invocation syntax, e.g.:
> 
> bool regexmatch(char[] str, char[] pat); // 1
> bool regexmatch(char[] pat)(char[] str, pat); // 2
> bool regexmatch(char[] pat, char[] str)(str, pat); // 3
> 
> void main(int argc, char[][] argv)
> {
>   regexmatch(argv[0], argv[1]); // goes to (1)
>   regexmatch(argv[0], ".+"); // goes to (2)
>   regexmatch("yah", ".+"); // goes to (3)
> }
> 
> Notice how the invocation syntax is identical --- an essential artifact.

Remember your proposal for a expression type which resolves to "does this expression compile"? That can be used here, along with expression aliasing, to test to see if it can be done at compile time, and then pick the right fork.
February 15, 2007
Walter Bright wrote:

>> Very good point. This could be solved by using some sort of conditional compilation construct on the bits you want to happen at runtime.
> 
> It's the other way around. Functions are always executed at runtime, unless they are in a context where a compile-time constant is *required*, such as for global variable initialization or template value arguments.

I know that's how it's implemented now. But generally, it's a good thing if as much as possible happens at compile time.

Unless you compile in debug mode, in which you want the compilation fast.

And like Bill said, you also don't want to decompress everything at compile time and blow up the executable. But that's not a problem if all you're doing is shrinking subtrees. Like in the case of that second sqrt call.

-- 
Michiel
February 15, 2007
Bill Baxter wrote:
> 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?

Tail recursion is a performance optimization, it has no effect on semantics, so it's not an issue for compile time execution.

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

Pure functions (the kind that can be compile time executed) don't need to be synchronized anyway.

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

Once more, there is never a situation where a function *might* or *might not* get executed at compile time. A function is *always* executed at runtime unless it is in a situation where it *must* be executed at compile time, such as in an initializer for a global.
February 15, 2007
Walter Bright wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>> What we need is allow a means to overload a function with a template, in
>> a way that ensures unified invocation syntax, e.g.:
>>
>> bool regexmatch(char[] str, char[] pat); // 1
>> bool regexmatch(char[] pat)(char[] str, pat); // 2
>> bool regexmatch(char[] pat, char[] str)(str, pat); // 3
>>
>> void main(int argc, char[][] argv)
>> {
>>   regexmatch(argv[0], argv[1]); // goes to (1)
>>   regexmatch(argv[0], ".+"); // goes to (2)
>>   regexmatch("yah", ".+"); // goes to (3)
>> }
>>
>> Notice how the invocation syntax is identical --- an essential artifact.
> 
> Remember your proposal for a expression type which resolves to "does this expression compile"? That can be used here, along with expression aliasing, to test to see if it can be done at compile time, and then pick the right fork.

It could indeed; I'm just hoping it can be properly cloaked away (e.g. in a library) at little cognitive cost to both the user and library developer. I assume it will be something often asked for.

Many Perl coders probably have no idea that:

$a =~ ".*=.*";

is faster than, and handled very, very differently, from:

$a =~ $b;

where $b is a dynamic variable. They just use the uniform syntax and let the compiler do whatever the hell it has to do to generate good code. We should make that kind of partial evaluation easy to define and implement.


Andrei
February 15, 2007
Sean Kelly wrote:
> 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
> 
> Huh, and Bjarne co-authored that proposal.  I wonder what the reason is for all the restrictions.

I'm guessing, but I suppose they wished to be as conservative as possible in order to avoid the unimplementable debacle exported templates were.
February 15, 2007
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14