On Tuesday, 23 July 2013 at 22:38:35 UTC, Yota wrote:
On Tuesday, 23 July 2013 at 20:11:21 UTC, JS wrote:
Your code doesn't exactly do what I wanted but probably because I wasn't clear... I think it is modifiable and solves the problem I was having(again, assuming your code is correct).

Note though that something like

string x = "asd"
join(x,...); // x is compile time known and should be joined at compile time. Not sure if D is smart enough to get this one?

When I get some time later I'll check your code out, what I want to do is get something like

string x = join(a, b, "a", "b"); to produce the same code as
string x = a~b~"ab";

(no looping using for each except for string arrays)

Thanks!


Don't forget that tuples can store more than just types! See this for instance.

  import std.stdio;

  typeof(Xs[0]) sum(Xs...)()
  {
      pragma(msg, Xs); // tuple(1, 2, 3)
      typeof(Xs[0]) y;
      foreach(x; Xs) y ~= x;
      return y;
  }

  int main() {
      auto n = sum!(1, 2, 3);
      enum m = sum!(1, 2, 3);

      pragma(msg, typeof(n)); // int
      writeln(n); // 6
      writeln(m); // 6

      return 0;
  }

Works great. When I comment out the 'sum!("1", "2", "3")' and replace it with a literal '6', the compiled EXE is byte for byte exactly the same. You can exchange the '+=' for '~=' and it will concatenate strings instead. Of course, now all arguments MUST be known at compile time, but that's no surprise.

PS: OK, just noticed that you were hoping to mix run time and compile time arguments. Oops....
Oh well, posting anyway because I think it's neat. lol

As for a~"B"~"C" compiling into a~"BC", I think we just need to work on constant folding in the compiler. (If it doesn't already do this anyway.)

Well, it's not that simple. Constant folding is easy when it is obvious to the compiler... but something buried in foreach loop that uses runtime and compile time objects is not obvious.

My three points out of the post is:

1. D needs some way to make doing this stuff easier.
2. It needs to be done! ;)
3. Goto 1.

I didn't realize D could even potentially do it, and still not sure if it can(have to check out T's post again and work with the code).

I think there is a lot of potential power behind such techniques with regard to optimization.

Suppose you are writing a matrix library. Wouldn't it be nice to have certain matrix computations that can be done at compile time actually done? (I suppose what I'm trying to do is extend the compiler's "constant folding" to be able to deal with much more complex cases).


Another way to potentially do it, I think, is for the compiler to automatically expand ctfe functions and replace runtime entities with "placeholder" code which is then expanded at runtime.

e.g., for a simple join

join(T...)(T t)
{
    string s;
    foreach(tt; t)
        s ~= tt;
    return s;
}

the compiler can unroll the loop to get

s ~= t[0]~t[1]~t[2]~...;

replace the compile time entities, e.g., suppose t[1] and t[3] are known at compile time at the invocation, then

s ~= t[0]~"abcd"~t[2]~"asdf";

then this code could be used inline for the join call instead of the actual code. The key here is there is no dependence on the for loop. If all arguments are compile-time evaluable, then s could be just a reference lookup to a static string. If it can't be done, then no big deal, it is optimized as far as it can go. Only if all arguments passed are runtime entities will the exact code be used.

This seems like it would take a pretty smart compiler and possibly it would have issues in some many cases. I personally don't mind writing the code itself but it seems pretty complex, and having no way to debug the code generation easily(AFAIK) makes it difficult to do.

Possibly using version(ctfe) can help... I'll work on it when I get a chance...

Reply via email to