Bug 7675 – std.format needs better exception messages

Status
RESOLVED
Resolution
WORKSFORME
Severity
enhancement
Priority
P2
Component
phobos
Product
D
Version
D2
Platform
All
OS
All
Creation time
2012-03-08T17:53:00Z
Last change time
2013-05-24T05:50:11Z
Assigned to
nobody
Creator
andrej.mitrovich

Comments

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"