Mixin and function template?
Frits van Bommel
fvbommel at REMwOVExCAPSs.nl
Wed Feb 28 16:56:20 PST 2007
renoX wrote:
> Frits van Bommel a écrit :
>> renoX wrote:
>>> 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..
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 :).
More information about the Digitalmars-d-learn
mailing list