Comment #0 by andrej.mitrovich — 2012-03-08T17:53:14Z
import std.string;
void main()
{
string res = format("%s %s", 1);
}
std.format.FormatException@std\format.d(62): format error
format() should verify that the count of parameters matches the format specifier and give a nice error message like this:
std.format.FormatException@std\format.d(62): format error: Expected 2 parameters, got 1.
format() is one of the most used functions in Phobos so I think this is pretty important.
Comment #1 by andrej.mitrovich — 2012-05-26T09:54:34Z
If anyone else is annoyed by this you can use a workaround like this:
/** Workaround for Issue 7675 - std.format needs better exception messages */
string safeFmt(string file = __FILE__, int line = __LINE__, T...)(string fmt, T args)
{
auto specCount = count(fmt, "%s");
enforce(specCount == T.length,
new Exception(format("Arg count %s doesn't match spec count %s.", T.length, specCount), file, line));
return format(fmt, args);
}
That implies using %s exclusively and it only throws on argument count mismatch, but it's still a shitload better than "Error occurred somewhere, have fun debugging!".
Throwing exceptions in Phobos with no information on what went wrong should be *banned*.
Comment #2 by bearophile_hugs — 2012-05-26T11:57:34Z
(In reply to comment #1)
> enforce(specCount == T.length,
> new Exception(format("Arg count %s doesn't match spec count %s.",
> T.length, specCount), file, line));
Andrei wants formatted printing to be sloppy, so currently this doesn't raise an error:
import std.string;
void main() {
string res = format("%s ", 1, 2);
}
Comment #3 by andrej.mitrovich — 2012-05-26T12:42:38Z
(In reply to comment #2)
> Andrei wants formatted printing to be sloppy, so currently this doesn't raise
> an error..
Right, but the OP code does raise an exception except it gives absolutely no information whatsoever on what went wrong. Reading a stack trace of a dozen template instantiations doesn't help either.
Comment #4 by andrej.mitrovich — 2013-01-24T16:11:25Z
The situation seems to be better now:
import std.string;
void main()
{
string res = format("%s %s", 1);
}
> std.format.FormatException@D:\dmd-git\dmd2\windows\bin\..\..\src\phobos\std\format.d(431): Orphan format specifier: %%s %s
Slightly confusing message, as it thought it was going to print '%s' but it prints the entire string.
And the other message:
import std.string;
void main()
{
string res = format("%s %s", 1, 2, 3);
}
> std.format.FormatException@D:\dmd-git\dmd2\windows\bin\..\..\src\phobos\std\string.d(2536): Orphan format arguments: args[2..3]
I'm quite satisfied that this was implemented. Although the stack trace still sucks as I've yet to get proper line numbers.
But at least I don't have to count the specifiers in a wrapper function, I just have to catch FormatExceptions:
string safeFmt(string file = __FILE__, size_t line = __LINE__, Args...)(string fmt, Args args)
{
try
{
return format(fmt, args);
}
catch (FormatException exc)
{
exc.file = file;
exc.line = line;
throw exc;
}
}
void main()
{
auto x = safeFmt("%s", 1, 2);
}
How great is that?
Comment #5 by luk.wrzosek — 2013-05-22T10:33:44Z
Why this sample compiles fine if it always frows an exception ?
import std.string;
void main()
{
string res = format("%s %s", 1);
}
Comment #6 by andrej.mitrovich — 2013-05-22T14:39:28Z
(In reply to comment #5)
> Why this sample compiles fine if it always throws an exception ?
Because the string argument is passed at runtime.
Comment #7 by luk.wrzosek — 2013-05-24T05:50:11Z
I know that already, but why it was written like that?
It would be useful to have this kind of error thrown at compile time, wouldn't it"