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