www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Mixin and function template?

reply renoX <renosky free.fr> writes:
Hello,

I have a template which contain a single function:
template sputf(A...)
{
	char[] call()
	{
		auto fd=std.c.stdio.fopen("tmp_file", "w+");
		mixin(`fwritef(fd,`~Fmt!(A)~`);`);	
		std.c.stdio.fclose(fd);
		auto res = cast(char[])read("tmp_file");
		return res;
	}
}
At the call site, I have to do the following:
	mixin sputf!("%d{x}") P1;
	res = P1.call();
which is quite ugly, so I'd like to convert the code in a 'function template'
but when I do this, I don't manage to call the function without failure..
Does someone knows how to do it?

Regards,
renoX
Feb 28 2007
next sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
renoX wrote:
 I have a template which contain a single function:

Let's start with that code...
 template sputf(A...)
 {
 	char[] call()
 	{
 		auto fd=std.c.stdio.fopen("tmp_file", "w+");

 		mixin(`fwritef(fd,`~Fmt!(A)~`);`);	

This line is equivalent to: fwritef(fd, Fmt!(A)); no mixin() required.
 		std.c.stdio.fclose(fd);
 		auto res = cast(char[])read("tmp_file");

So basically, you're creating a temporary file, write some formatted output to it, then open it and put the contents in an allocated buffer? Why not just: auto res = std.string.format(Fmt!(A)); ? That should allocate a string and fill it with with the formatted data. AFAICT it's equivalent to the above code, except the code above creates a file to do it, and so can get into trouble if multiple versions of it get run at the same time from the same directory...
 		return res;

Also, you forgot to delete the file before returning. Unless that was intended? (I didn't think so :P)
 	}
 }

So: --- template sputf(A...) { char[] call() { return std.string.format(Fmt!(A)); } } --- should be pretty much identical to your code, except for tempfile-related issues in your version.
 At the call site, I have to do the following:
 	mixin sputf!("%d{x}") P1;
 	res = P1.call();
 which is quite ugly, so I'd like to convert the code in a 'function template'
but when I do this, I don't manage to call the function without failure..
 Does someone knows how to do it?

Well, presumably the function needs to access (local?) variable 'x'. That means you can't avoid using some kind of mixin if you want to do this. But I don't think the code left in the template is very ugly, so you could also just use it directly, like this: --- import std.string; // ... some stuff here ... // example function using Fmt!() char[] func(int x) { char[] res = format(Fmt!("%d{x}")); return res; } --- Which is probably cleaner than anything you'll get without: a) changing format() to be compile-time executable, or b) waiting until Walter sufficiently improves compile-time execution to allow current format() to be usable, or c) implementing a compile-time format-like function yourself (either as a compile-time executable function or through template meta programming).
Feb 28 2007
parent reply renoX <renosky free.fr> writes:
Frits van Bommel a écrit :
 renoX wrote:
 I have a template which contain a single function:

Let's start with that code...
 template sputf(A...)
 {
     char[] call()
     {
         auto fd=std.c.stdio.fopen("tmp_file", "w+");

         mixin(`fwritef(fd,`~Fmt!(A)~`);`);   

This line is equivalent to: fwritef(fd, Fmt!(A)); no mixin() required.

In theory yes, in practice when I tried fwritef(fd, Fmt!(A)); it didn't work..
 
         std.c.stdio.fclose(fd);
         auto res = cast(char[])read("tmp_file");

So basically, you're creating a temporary file, write some formatted output to it, then open it and put the contents in an allocated buffer? Why not just: auto res = std.string.format(Fmt!(A));

Because I didn't know this function, thanks for the suggestion. When I tried it didn't work though, unfortunately..
 That should allocate a string and fill it with with the formatted data. 
 AFAICT it's equivalent to the above code, except the code above creates 
 a file to do it, and so can get into trouble if multiple versions of it 
 get run at the same time from the same directory...
 
         return res;

Also, you forgot to delete the file before returning. Unless that was intended? (I didn't think so :P)

No, a small mistake.
 
     }
 }

So: --- template sputf(A...) { char[] call() { return std.string.format(Fmt!(A)); } } --- should be pretty much identical to your code, except for tempfile-related issues in your version.
 At the call site, I have to do the following:
     mixin sputf!("%d{x}") P1;
     res = P1.call();
 which is quite ugly, so I'd like to convert the code in a 'function 
 template' but when I do this, I don't manage to call the function 
 without failure..
 Does someone knows how to do it?

Well, presumably the function needs to access (local?) variable 'x'. That means you can't avoid using some kind of mixin if you want to do this.

It's not the mixin that I want to get rid of (I can't) but what I'd like is to rename the function call sputf and to have just one function call, this works for templates, but not for template function, weird..
 
 But I don't think the code left in the template is very ugly, so you 
 could also just use it directly, like this:
 ---
 import std.string;
 
 // ... some stuff here ...
 
 // example function using Fmt!()
 char[] func(int x) {
         char[] res = format(Fmt!("%d{x}"));
     return res;
 }
 ---
 Which is probably cleaner than anything you'll get without:
 a) changing format() to be compile-time executable, or
 b) waiting until Walter sufficiently improves compile-time execution to 
 allow current format() to be usable, or
 c) implementing a compile-time format-like function yourself (either as 
 a compile-time executable function or through template meta programming).

Fmt! is doing c), it is limitated of course because I choose not to parse a string and templates do not accept expressions.. The fact that format is not working, nor fwrite(fd but mixin(fwrite(fd works make me thing of a bug.. renoX
Feb 28 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
renoX wrote:
 Frits van Bommel a écrit :
 renoX wrote:
         mixin(`fwritef(fd,`~Fmt!(A)~`);`);   

This line is equivalent to: fwritef(fd, Fmt!(A));

In theory yes, in practice when I tried fwritef(fd, Fmt!(A)); it didn't work..

Oh, sorry. I should have seen that Fmt!() generates the arguments as a string, not a tuple. So you'd still need the mixin wrapper here.
         std.c.stdio.fclose(fd);
         auto res = cast(char[])read("tmp_file");

So basically, you're creating a temporary file, write some formatted output to it, then open it and put the contents in an allocated buffer? Why not just: auto res = std.string.format(Fmt!(A));

Because I didn't know this function, thanks for the suggestion. When I tried it didn't work though, unfortunately..

This should be equivalent to your original[1]: auto res = mixin("std.string.format(" ~ Fmt!(A) ~ ")"); [1]: Of course, my previous suggestion *should* have been equivalent as well. Unfortunately it wasn't ;).
 At the call site, I have to do the following:
     mixin sputf!("%d{x}") P1;
     res = P1.call();
 which is quite ugly, so I'd like to convert the code in a 'function 
 template' but when I do this, I don't manage to call the function 
 without failure..
 Does someone knows how to do it?

Well, presumably the function needs to access (local?) variable 'x'. That means you can't avoid using some kind of mixin if you want to do this.

It's not the mixin that I want to get rid of (I can't) but what I'd like is to rename the function call sputf and to have just one function call, this works for templates, but not for template function, weird..

You could have a compile-time function generate a string that calls the appropriate code. Here's what I came up with: --- import std.stdio; import std.string; /** dummy Fmt!() for testing. This example assumes it accepts a * single string and returns format() parameters in string form. */ template Fmt(char[] A) { const char[] Fmt = `"%d", x`; } /** Ensures escape codes and quotes in strings are escaped themselves. * Not thoroughly checked, but the idea is that the following should * hold for all strings: * --- * string == mixin(escape(string)); * --- */ char[] escape(char[] string) { char[] result = "\""; foreach (c; string) { if (c == '\\') result ~= "\\\\"; else if (c == '"') result ~= "\\\""; else result ~= c; } result ~= "\""; return result; } /** The input must be a format string with embedded "%d{var}"-style * formatting commands */ char[] sputf(char[] string) { return "mixin(`std.string.format(` ~ Fmt!(" ~ escape(string) ~ ") ~ `)`)"; } void main(char[][] args) { char[] ret; int x = 2007; ret = mixin(sputf("%d{x}")); writefln("%s", ret); } --- As short as it is, it took me a while to get it that way. This is playing with meta-levels. It mixes in a string containing a mixin expression. It used to be even worse though: At first the sputf() function was just a wrapper around an adapted sputf!() template, but all the call() function did was return a mixed-in expression, which was then wrapped into a string that - when mixed in - assigned the second-level mixed-in result to a variable passed by name. So it mixed in a string, that mixed in a template, that mixed in an expression -- a three-level mixin. (Careful: multiple meta-levels like that can get really confusing really quick :P) Then I figured, that template mixin (sputfImpl!(), specifically the call() member) must be inlinable ;). After adding an escape() function around the format string, the result is what you see above: short but sweet. I hope you agree that --- ret = mixin(sputf("%d{x}")); --- is a pretty good syntax :).
Feb 28 2007
parent reply renoX <renosky free.fr> writes:
Frits van Bommel a écrit :
[cut]
 /** The input must be a format string with embedded "%d{var}"-style
  *  formatting commands
  */
 char[] sputf(char[] string) {
     return "mixin(`std.string.format(` ~ Fmt!(" ~ escape(string) ~ ") ~ 
 `)`)";
 }
 
 void main(char[][] args) {
     char[] ret;
     int x = 2007;
     
     ret = mixin(sputf("%d{x}"));
     
     writefln("%s", ret);
 }

The difference between your sputf and mine is that mine take a tuple sputf(A...) instead of a string, is it be possible to have a function template take a tuple as an argument that is to say to have something like char[] sputf(A...)() { return "std.string.format("~Fmt!(A) ~ ");"; } And still call it like you do above? It doesn't work when I try to do this, I don't understand why..
 ---
 
 As short as it is, it took me a while to get it that way.
 This is playing with meta-levels. It mixes in a string containing a 
 mixin expression. It used to be even worse though:
 At first the sputf() function was just a wrapper around an adapted 
 sputf!() template, but all the call() function did was return a mixed-in 
 expression, which was then wrapped into a string that - when mixed in - 
 assigned the second-level mixed-in result to a variable passed by name.
 So it mixed in a string, that mixed in a template, that mixed in an 
 expression -- a three-level mixin. (Careful: multiple meta-levels like 
 that can get really confusing really quick :P)

Yes, I find it very easy to be confused.
 Then I figured, that template mixin (sputfImpl!(), specifically the 
 call() member) must be inlinable ;).
 
 After adding an escape() function around the format string, the result 
 is what you see above: short but sweet.
 
 I hope you agree that
 ---
     ret = mixin(sputf("%d{x}"));
 ---
 is a pretty good syntax :).

I agree, but it's a limited one: you cannot do mixin(sputf("%d",x)) I wanted to syntax to be compatible with the old printf syntax.. Regards, renoX
Mar 01 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
renoX wrote:
 Frits van Bommel a écrit :
 [cut]
 /** The input must be a format string with embedded "%d{var}"-style
  *  formatting commands
  */
 char[] sputf(char[] string) {
     return "mixin(`std.string.format(` ~ Fmt!(" ~ escape(string) ~ ") 
 ~ `)`)";
 }

 void main(char[][] args) {
     char[] ret;
     int x = 2007;
         ret = mixin(sputf("%d{x}"));
         writefln("%s", ret);
 }

The difference between your sputf and mine is that mine take a tuple sputf(A...) instead of a string, is it be possible to have a function template take a tuple as an argument that is to say to have something like char[] sputf(A...)() { return "std.string.format("~Fmt!(A) ~ ");"; } And still call it like you do above? It doesn't work when I try to do this, I don't understand why..

For one thing, the ';' shouldn't be there. And the call syntax changes slightly, you need to add the '!' to indicate they're template parameters instead of function parameters. (the function call parentheses can be left off due to property syntax) Then you get this: --- import std.stdio; import std.string; /** dummy Fmt!() for testing. This example assumes it accepts a * tuple and returns format() parameters in string form. */ template Fmt(A...) { const char[] Fmt = `"%d", x`; } char[] sputf(A...)() { return "std.string.format(" ~ Fmt!(A) ~ ")"; } void main(char[][] args) { char[] ret; int x = 2007; ret = mixin(sputf!("%d{x}")); writefln("%s", ret); } --- which seems to work.
 As short as it is, it took me a while to get it that way.
 This is playing with meta-levels. It mixes in a string containing a 
 mixin expression. It used to be even worse though:
 At first the sputf() function was just a wrapper around an adapted 
 sputf!() template, but all the call() function did was return a 
 mixed-in expression, which was then wrapped into a string that - when 
 mixed in - assigned the second-level mixed-in result to a variable 
 passed by name.
 So it mixed in a string, that mixed in a template, that mixed in an 
 expression -- a three-level mixin. (Careful: multiple meta-levels like 
 that can get really confusing really quick :P)

Yes, I find it very easy to be confused.

The above is actually much clearer in implementation. A bit less nice in call syntax, but not by much.
 Then I figured, that template mixin (sputfImpl!(), specifically the 
 call() member) must be inlinable ;).

 After adding an escape() function around the format string, the result 
 is what you see above: short but sweet.

 I hope you agree that
 ---
     ret = mixin(sputf("%d{x}"));
 ---
 is a pretty good syntax :).

I agree, but it's a limited one: you cannot do mixin(sputf("%d",x)) I wanted to syntax to be compatible with the old printf syntax..

Is the above what you were looking for?
Mar 01 2007
parent reply renoX <renosky free.fr> writes:
Frits van Bommel a écrit :
 renoX wrote:
 Frits van Bommel a écrit :
 [cut]
 /** The input must be a format string with embedded "%d{var}"-style
  *  formatting commands
  */
 char[] sputf(char[] string) {
     return "mixin(`std.string.format(` ~ Fmt!(" ~ escape(string) ~ ") 
 ~ `)`)";
 }

 void main(char[][] args) {
     char[] ret;
     int x = 2007;
         ret = mixin(sputf("%d{x}"));
         writefln("%s", ret);
 }

The difference between your sputf and mine is that mine take a tuple sputf(A...) instead of a string, is it be possible to have a function template take a tuple as an argument that is to say to have something like char[] sputf(A...)() { return "std.string.format("~Fmt!(A) ~ ");"; } And still call it like you do above? It doesn't work when I try to do this, I don't understand why..

For one thing, the ';' shouldn't be there.

Weird, the template that I had already for the 'writef equivalent' was: template putf(A...) { const char[] putf = "writef(" ~ Fmt!(A) ~ ");"; } Here the ';' didn't create a problem, it's string that in the sputf template function it creates a problem..
 And the call syntax changes 
 slightly, you need to add the '!' to indicate they're template 
 parameters instead of function parameters.

Yes.
 (the function call 
 parentheses can be left off due to property syntax)

I hadn't realised that the removal of the parenthesis was due to the property syntax..
 Then you get this:
 ---
 import std.stdio;
 import std.string;
 
 /** dummy Fmt!() for testing. This example assumes it accepts a
  *  tuple and returns format() parameters in string form.
  */
 template Fmt(A...) {
     const char[] Fmt = `"%d", x`;
 }
 
 char[] sputf(A...)()
 {
      return "std.string.format(" ~ Fmt!(A) ~ ")";
 }
 
 void main(char[][] args) {
     char[] ret;
     int x = 2007;
     
     ret = mixin(sputf!("%d{x}"));
     
     writefln("%s", ret);
 }
 ---
 which seems to work.

Yes, but what is a bit strange is that if x is an int variable res = mixin(sputf!("%d",x)); fails (it works if x is a const int) but mixin(putf!("%d",x)); works (putf being the template given above).
 As short as it is, it took me a while to get it that way.
 This is playing with meta-levels. It mixes in a string containing a 
 mixin expression. It used to be even worse though:
 At first the sputf() function was just a wrapper around an adapted 
 sputf!() template, but all the call() function did was return a 
 mixed-in expression, which was then wrapped into a string that - when 
 mixed in - assigned the second-level mixed-in result to a variable 
 passed by name.
 So it mixed in a string, that mixed in a template, that mixed in an 
 expression -- a three-level mixin. (Careful: multiple meta-levels 
 like that can get really confusing really quick :P)

Yes, I find it very easy to be confused.

The above is actually much clearer in implementation. A bit less nice in call syntax, but not by much.
 Then I figured, that template mixin (sputfImpl!(), specifically the 
 call() member) must be inlinable ;).

 After adding an escape() function around the format string, the 
 result is what you see above: short but sweet.

 I hope you agree that
 ---
     ret = mixin(sputf("%d{x}"));
 ---
 is a pretty good syntax :).

I agree, but it's a limited one: you cannot do mixin(sputf("%d",x)) I wanted to syntax to be compatible with the old printf syntax..

Is the above what you were looking for?

Yes, thanks a lot. renoX
Mar 01 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
renoX wrote:
 Frits van Bommel a écrit :
 renoX wrote:
 char[] sputf(A...)()
 {
      return "std.string.format("~Fmt!(A) ~ ");";
 }

 And still call it like you do above?
 It doesn't work when I try to do this, I don't understand why..

For one thing, the ';' shouldn't be there.

Weird, the template that I had already for the 'writef equivalent' was: template putf(A...) { const char[] putf = "writef(" ~ Fmt!(A) ~ ");"; } Here the ';' didn't create a problem, it's string that in the sputf template function it creates a problem..

There are three kinds of mixins[1]: mixin declarations, mixin statements and mixin expressions. Your putf string is used as a mixin statement, while the sputf string is used as a mixin expression. See http://www.digitalmars.com/d/changelog.html#new1_005 for the spec links, but essentially mixin statements generate statements (including any terminating ';'s) while mixin expressions just generate (sub)expressions, which don't contain ';'s. [1] excluding template mixins, which are a different beast altogether.
 Then you get this:
 ---
 import std.stdio;
 import std.string;

 /** dummy Fmt!() for testing. This example assumes it accepts a
  *  tuple and returns format() parameters in string form.
  */
 template Fmt(A...) {
     const char[] Fmt = `"%d", x`;
 }

 char[] sputf(A...)()
 {
      return "std.string.format(" ~ Fmt!(A) ~ ")";
 }

 void main(char[][] args) {
     char[] ret;
     int x = 2007;
         ret = mixin(sputf!("%d{x}"));
         writefln("%s", ret);
 }
 ---
 which seems to work.

Yes, but what is a bit strange is that if x is an int variable res = mixin(sputf!("%d",x)); fails (it works if x is a const int) but mixin(putf!("%d",x)); works (putf being the template given above).

The behaviors differ? That's a bit weird... They both use template parameters, so they should have the exact same restrictions AFAIK. [a bit of research later] I think this is a restriction of compile-time function evaluation. From http://www.digitalmars.com/d/function.html#interpretation : --- expressions in the function may not: [snip] * reference any global state or variables * reference any local static variables [snip] --- Those /could/ be interpreted to disallow alias template parameter usage... Luckily the fix is easy, just transform it to be similar to your putf template to avoid CTFE: --- template sputf(A...) { const sputf = "std.string.format(" ~ Fmt!(A) ~ ")"; } --- works perfectly fine, even with non-constant integer variables as parameters. And the call syntax didn't even change :).
Mar 01 2007
parent reply renoX <renosky free.fr> writes:
Frits van Bommel a écrit :
 renoX wrote:
 Frits van Bommel a écrit :
 renoX wrote:
 char[] sputf(A...)()
 {
      return "std.string.format("~Fmt!(A) ~ ");";
 }

 And still call it like you do above?
 It doesn't work when I try to do this, I don't understand why..

For one thing, the ';' shouldn't be there.

Weird, the template that I had already for the 'writef equivalent' was: template putf(A...) { const char[] putf = "writef(" ~ Fmt!(A) ~ ");"; } Here the ';' didn't create a problem, it's string that in the sputf template function it creates a problem..

There are three kinds of mixins[1]: mixin declarations, mixin statements and mixin expressions. Your putf string is used as a mixin statement, while the sputf string is used as a mixin expression. See http://www.digitalmars.com/d/changelog.html#new1_005 for the spec links, but essentially mixin statements generate statements (including any terminating ';'s) while mixin expressions just generate (sub)expressions, which don't contain ';'s. [1] excluding template mixins, which are a different beast altogether.
 Then you get this:
 ---
 import std.stdio;
 import std.string;

 /** dummy Fmt!() for testing. This example assumes it accepts a
  *  tuple and returns format() parameters in string form.
  */
 template Fmt(A...) {
     const char[] Fmt = `"%d", x`;
 }

 char[] sputf(A...)()
 {
      return "std.string.format(" ~ Fmt!(A) ~ ")";
 }

 void main(char[][] args) {
     char[] ret;
     int x = 2007;
         ret = mixin(sputf!("%d{x}"));
         writefln("%s", ret);
 }
 ---
 which seems to work.

Yes, but what is a bit strange is that if x is an int variable res = mixin(sputf!("%d",x)); fails (it works if x is a const int) but mixin(putf!("%d",x)); works (putf being the template given above).

The behaviors differ? That's a bit weird... They both use template parameters, so they should have the exact same restrictions AFAIK. [a bit of research later] I think this is a restriction of compile-time function evaluation. From http://www.digitalmars.com/d/function.html#interpretation : --- expressions in the function may not: [snip] * reference any global state or variables * reference any local static variables [snip] --- Those /could/ be interpreted to disallow alias template parameter usage... Luckily the fix is easy, just transform it to be similar to your putf template to avoid CTFE: --- template sputf(A...) { const sputf = "std.string.format(" ~ Fmt!(A) ~ ")"; } --- works perfectly fine, even with non-constant integer variables as parameters. And the call syntax didn't even change :).

Great! Thanks a lot! renoX
Mar 02 2007
parent renoX <renosky free.fr> writes:
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

Here's the result.

Fixing my problems with sputf! helped me shorten the self-test part in 
the main function.

So thanks again.

renoX
Mar 02 2007
prev sibling parent reply Hasan Aljudy <hasan.aljudy gmail.com> writes:
renoX wrote:
 Hello,
 
 I have a template which contain a single function:
 template sputf(A...)
 {
 	char[] call()
 	{
 		auto fd=std.c.stdio.fopen("tmp_file", "w+");
 		mixin(`fwritef(fd,`~Fmt!(A)~`);`);	
 		std.c.stdio.fclose(fd);
 		auto res = cast(char[])read("tmp_file");
 		return res;
 	}
 }
 At the call site, I have to do the following:
 	mixin sputf!("%d{x}") P1;
 	res = P1.call();
 which is quite ugly, so I'd like to convert the code in a 'function template'
but when I do this, I don't manage to call the function without failure..
 Does someone knows how to do it?
 
 Regards,
 renoX

I wrote some code so that you could print local variables or expressions by wrapping them with {{ double braces }} inside the string (this is a Django idiom). The code is not so stable as it doesn't do anything about escaping and stuff .. and it's not really tested at all .. except for one use-case; it's the intended typical usage: auto name = "hasan"; mixin( bang( "hello {{name}}, how are you?" ) ); the idea is to replace bang("string1 {{expr}} string2") with writefln( "string1", expr, "string2" ); Here's the code, it's written in an ugly aggressive way because it was my first attempt to play with mixins & compile-time functions, so I stayed as low-level as possible. ------------ import std.stdio; char[] parse( char[] string ) { char[] result = ""; int index = 0; while( index < string.length ) { //scan for {{ bool sequence = false; int start = index; while(index < string.length) { if( (index < string.length-2) ) { if( (string[index] == '{') && (string[index+1] == '{') ) { sequence = true; break; } } index++; } auto raw = string[start..index]; //this holds the contents of string up to the first "{{" if there is one. if( result.length > 0 ) result = result ~ ", "; result = result ~ `"` ~ raw ~ `"`; if( sequence ) { index+= 2; start = index; //look for }} while( (index < string.length-2) ) { if( (string[index] == '}') && (string[index+1] == '}') ) break; index++; } auto exp = string[start..index]; result = result ~ ", " ~ exp; index += 2; } } return result; } char[] bang( char[] expr ) { expr = parse(expr); return `writefln(` ~ expr ~ `);`; } void main() { auto name = "hasan"; mixin( bang( "hello {{name}}, how are you?" ) ); } ----------
Mar 01 2007
parent renoX <renosky free.fr> writes:
Hasan Aljudy a écrit :
 
 
 renoX wrote:
 Hello,

 I have a template which contain a single function:
 template sputf(A...)
 {
     char[] call()
     {
         auto fd=std.c.stdio.fopen("tmp_file", "w+");
         mixin(`fwritef(fd,`~Fmt!(A)~`);`);   
         std.c.stdio.fclose(fd);
         auto res = cast(char[])read("tmp_file");
         return res;
     }
 }
 At the call site, I have to do the following:
     mixin sputf!("%d{x}") P1;
     res = P1.call();
 which is quite ugly, so I'd like to convert the code in a 'function 
 template' but when I do this, I don't manage to call the function 
 without failure..
 Does someone knows how to do it?

 Regards,
 renoX

I wrote some code so that you could print local variables or expressions by wrapping them with {{ double braces }} inside the string (this is a Django idiom).

Thanks for your code, the syntax I used is inspired from Ruby #{} except that I thought that in printf '%' is the escape char, that's why I'm using %s{} or %d{} (and %{ as equivalent to '{') We're doing more or less the same thing, except that my implementation takes a tuple instead of just one string which allows to be a little bit compatible with printf: mixin(putf!("%d",x)) works. But I have a hard time making the equivalent of for format/sprintf.. renoX
 
 The code is not so stable as it doesn't do anything about escaping and 
 stuff .. and it's not really tested at all .. except for one use-case;
 it's the intended typical usage:
 
 auto name = "hasan";
 mixin( bang( "hello {{name}}, how are you?" ) );
 
 the idea is to replace bang("string1 {{expr}} string2") with
 writefln( "string1", expr, "string2" );
 
 Here's the code, it's written in an ugly aggressive way because it was 
 my first attempt to play with mixins & compile-time functions, so I 
 stayed as low-level as possible.
 ------------
 import std.stdio;
 
 char[] parse( char[] string )
 {
     char[] result = "";
     int index = 0;
     while( index < string.length )
     {
         //scan for {{
         bool sequence = false;
         int start = index;
         while(index < string.length)
         {
             if( (index < string.length-2) )
             {
                 if( (string[index] == '{') && (string[index+1] == '{') )
                 {
                     sequence = true;
                     break;
                 }
             }
             index++;
         }
         auto raw = string[start..index]; //this holds the contents of 
 string up to the first "{{" if there is one.
 
         if( result.length > 0 )
             result = result ~ ", ";
         result = result ~ `"` ~ raw ~ `"`;
 
         if( sequence )
         {
             index+= 2;
             start = index;
             //look for }}
             while( (index < string.length-2) )
             {
                 if( (string[index] == '}') && (string[index+1] == '}') )
                     break;
                 index++;
             }
             auto exp = string[start..index];
             result = result ~ ", " ~ exp;
             index += 2;
         }
     }
 
     return result;
 }
 
 char[] bang( char[] expr )
 {
     expr = parse(expr);
     return `writefln(` ~ expr ~ `);`;
 }
 
 void main()
 {
     auto name = "hasan";
     mixin( bang( "hello {{name}}, how are you?" ) );
 }
 ----------
 

Mar 01 2007