www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Forcing compile time evaluation of pure functions

reply scarrow <shawn.baird gmail.com> writes:
Hey all,

I'd like to embed hashed strings into my code.  The C++ version of this engine
ran an external tool to preprocess the files.  In D my strongly pure function
is only evaluated if I assign it to something like an enum or invoke it from a
template.  So the following generate compile time hashes:

    enum blort = Hash("foo");
    f(CHash!("foo"));

Annoyingly, however, I can't do the following at compile time:

    f(Hash("foo"));

I'm not sure what the point is in distinguishing between these two cases.  If
it is a properly pure function there should be no harm in doing a compile time
evaluation.  Ideally (and maybe this is being purposely avoided) I want to be
able to write:

    string s = "bar";
    f(Hash("foo"));    // invoke the compile time version and pass a constant
to f
    f(Hash(s));    // invoke the runtime version and pass the result to f
Jun 29 2011
next sibling parent scarrow <shawn.baird gmail.com> writes:
Oh, I also wanted to mention that although ideally I'd be able to invoke the
compile time and runtime versions identically and have it automatically select,
I'm also worried about accidentally invoking the runtime version when I should
have been using the compile time version.  I can't think of a way to make it:

    string s = "foo";
    auto h = Hash("foo");    // I'd like it to fail but doesn't
    auto i = CHash!("foo");  // works fine (compile time)
    auto j = Hash(s);        // works fine (runtime)
    auto k = CHash!(s);      // fails as it should
Jun 29 2011
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
scarrow:

 Annoyingly, however, I can't do the following at compile time:
 
     f(Hash("foo"));
 
 I'm not sure what the point is in distinguishing between these two cases.

Walter has decided that he doesn't like the D compiler to arbitrary run at compile time arbitrary long to run code. This is named partial compilation and it has some traps. In theory I agree with you that I'd like the compiler to be smarter, but in practice Walter prefers control here, so DMD runs compile-time functions only if you explicitly ask their result to be known at compile-time. Note that in D you are able to run at compile time functions that are pure just in the execution path that's used at compile-time, even if on the whole they are not pure. This works: int x; int foo(bool b, int y) { if (b) return x; else return y; } enum result = foo(false, 10);
 I want to be able to write:
 
     string s = "bar";
     f(Hash("foo"));    // invoke the compile time version and pass a constant
to f
     f(Hash(s));    // invoke the runtime version and pass the result to f

Is this good enough? /** To execute a function at compile time. */ template StaticEval(A...) { enum typeof(A[0]) StaticEval = A[0]; } void f(size_t) {} size_t Hash(string s) { return 0U; } void main() { f(Hash("foo")); f(StaticEval!(Hash("foo"))); } The second Hash runs at compile-time, there is only one call to _D4test4HashFAyaZk (compiled with -O -release, without -inline): __Dmain comdat L0: push EAX push dword ptr FLAT:_DATA[0Ch] push dword ptr FLAT:_DATA[08h] call near ptr _D4test4HashFAyaZk call near ptr _D4test1fFkZv xor EAX,EAX call near ptr _D4test1fFkZv xor EAX,EAX pop ECX ret Bye, bearophile
Jun 30 2011
parent reply scarrow <scarrow cyberverse.com> writes:
I think invoking a template to call the pure function (StaticEval!(Hash("foo"))
isn't much different from StaticHash!("foo").  You still have to explicitly know
whether you're dealing with a compile time constant or not.  I'd really like to
figure out how to have Hash("foo") be static and Hash(variable) be dynamic.
Jul 14 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
scarrow:

 I'd really like to figure out how to have Hash("foo") be static and
Hash(variable) be dynamic.

In GCC there is a way to (sometimes) do it, see the __builtin_constant_p here: http://www.delorie.com/gnu/docs/gcc/gcc_81.html Time ago I have asked for something similar in D too, because I think it allows to implement a poor's man manual "partial compilation" using templates. Maybe it's worth asking about this in the main D newsgroup. But before asking, it's better to have few use cases examples :-) Bye, bearophile
Jul 14 2011
parent bearophile <bearophileHUGS lycos.com> writes:
 In GCC there is a way to (sometimes) do it, see the __builtin_constant_p here:
 http://www.delorie.com/gnu/docs/gcc/gcc_81.html

Google code search gives about 8,100 answers: http://www.google.com/codesearch#search/&q=%22__builtin_constant_p%22&type=cs Bye, bearophile
Jul 14 2011
prev sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Thu, 30 Jun 2011 07:11:44 +0200, scarrow <shawn.baird gmail.com> wrote:

 Hey all,

 I'd like to embed hashed strings into my code.  The C++ version of this  
 engine
 ran an external tool to preprocess the files.  In D my strongly pure  
 function
 is only evaluated if I assign it to something like an enum or invoke it  
 from a
 template.  So the following generate compile time hashes:

     enum blort = Hash("foo");
     f(CHash!("foo"));

 Annoyingly, however, I can't do the following at compile time:

     f(Hash("foo"));

 I'm not sure what the point is in distinguishing between these two  
 cases.  If
 it is a properly pure function there should be no harm in doing a  
 compile time
 evaluation.

Actually, there might. Pure functions are allowed to depend upon the immutable global variables, whose values may be calculated at startup (see static this) -- Simen
Jun 30 2011