Exceptional coding style
Artur Skawina
art.08.09 at gmail.com
Tue Jan 15 04:43:46 PST 2013
On 01/15/13 12:21, bearophile wrote:
> Artur Skawina:
>
>> Library territory. There's no need to put this in a D compiler.
>
> One of the threads about possible ways to allow to implement that in library code:
>
> http://forum.dlang.org/thread/nxhsgwliuwdgidaoudud@forum.dlang.org
>
>
>> Except if you'd like to have 'printf("%.2g", d)' instead of 'printf!"%.2g"(d)' syntax.
>
> In some cases I don't mind a syntax like 'printf!"%.2g"(d)'. But I'd like D to offer ways to remove/avoid template bloat in most of those cases.
You can't both avoid template bloat *and* statically check the arguments.
Statically checking dynamic data is not possible, obviously. But it's not
always a problem, as as long as everything is properly inlined the overhead
can be /less/ than zero. Anyway, a way to do these check right now could be
something like:
auto printf(string fmt, A...)(A a) /*@inline*/ {
static bool isFlag(char c) {
switch (c) {
case '0': case '#': case '-': case ' ': case '+':
case '\'': case 'I': // Non-std.
return true;
default: return false;
}
}
static bool checkArgs(B...)(string fmt) {
if (!__ctfe)
assert(0, "This function relies on bounds checks happening at CT");
while (fmt.length && fmt[0]!='%')
fmt = fmt[1..$];
if (fmt.length==0)
return true;
static if (B.length==0)
return fmt.length==0;
else {
size_t skip = 1;
// Flags
while (isFlag(fmt[skip]))
++skip;
// Width
while (fmt[skip]>='0' && fmt[skip]<='9')
++skip;
// Precision
// XXX skip \.[0-9]* , \.\*, \.[0-9]+\$
// Length modifier
// XXX skip them.
// Conversion spec
if (
(fmt[skip]=='d' && is(B[0]==int))
|| (fmt[skip]=='g' && is(B[0]==double))
|| (fmt[skip]=='s' && is(typeof(cast()*B[0])==char))
/* XXX etc */
)
return checkArgs!(B[1..$])(fmt[skip+1..$]);
assert(0, "printf format error: '" ~ fmt ~ "', remaining args: " ~ B.stringof);
}
}
static assert(checkArgs!A(fmt), "Invalid or unsupported printf args");
import si = std.stdio, std.string;
return si.printf(toStringz(fmt), a);
}
void main() {
printf!"Pi == %d.%d != %3d\n"(3, 14, 314);
printf!"Pi == %d.%d == %g\n"(3, 14, 3.14);
printf!"Pi == %d.%d == %g == %s\n"(3, 14, 3.14, "3.14".ptr);
// correctly flagged as invalid:
//printf!"%"(42);
}
But ideally the syntax should be
printf(A...)(static string s, A a)
which would be "lowered" to the equivalent of
printf(string s, A...)(A a)
and similarly:
printf(A...)(alias a, A a)
should behave as
print(alias a, A...)(A a)
Having this work just for templated functions would probably be ok.
artur
More information about the Digitalmars-d
mailing list