www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - Bug in std.format.doFormat?

reply Deewiant <deewiant.doesnotlike.spam gmail.com> writes:
Note how the format string doesn't change but the order of the arguments does:

--
import std.string, std.stdio;

void main() {
	printf("%s %d\n", toStringz("foo"), 5); // "foo 5"
	
	// printf("%s %d", 5, toStringz("foo")); // access violation
	
	writefln("%s %d", "foo", 5); // "foo 5"
	
	writefln("%s %d", 5, "foo"); // "5 foo"??
	
	char[] s = format("%s %d", "foo", 5);
	writefln(s); // "foo 5"
	
	s = format("%s %d", 5, "foo");
	writefln(s); // "5 foo"??
}
--

Or, to clarify:

When using printf(), if the arguments do not match the format string exactly,
_including their order_, an access violation occurs.

When using writef(), or std.string.format(), one can pass ("%s %d", 5, "foo")
and get the same result as from ("%d %s", 5, "foo") or ("%s %d", "foo", 5), even
though, in the former case, 5 does not match "%s" and "foo" does not match "%d".
That is, the order of the arguments (or, if you prefer to think that way, the
order of the types of format strings) does not matter.

The ? in the title about whether this is a bug in std.format.doFormat comes from
me not being sure whether the bug lies there or not, but since both the writef
functions and std.string.format() use doFormat() internally (I looked at the
Phobos source that much) I presume that's where the problem lies.

Of course this could be a bug in the documentation: there it is said that
"[m]ismatched arguments and formats result in a FormatError being thrown." Some
cases in the above example certainly seem mismatched to me, yet nothing was
thrown. It may be this is meant to happen (which I doubt, it just doesn't make
sense), in which case the documentation needs to be corrected.
Feb 11 2006
next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Deewiant" <deewiant.doesnotlike.spam gmail.com> wrote in message 
news:dsljv8$2r8b$1 digitaldaemon.com...
 Note how the format string doesn't change but the order of the arguments 
 does:

 --
 import std.string, std.stdio;

 void main() {
 printf("%s %d\n", toStringz("foo"), 5); // "foo 5"

 // printf("%s %d", 5, toStringz("foo")); // access violation

 writefln("%s %d", "foo", 5); // "foo 5"

 writefln("%s %d", 5, "foo"); // "5 foo"??

 char[] s = format("%s %d", "foo", 5);
 writefln(s); // "foo 5"

 s = format("%s %d", 5, "foo");
 writefln(s); // "5 foo"??
 }
 --

 Or, to clarify:

 When using printf(), if the arguments do not match the format string 
 exactly,
 _including their order_, an access violation occurs.

 When using writef(), or std.string.format(), one can pass ("%s %d", 5, 
 "foo")
 and get the same result as from ("%d %s", 5, "foo") or ("%s %d", "foo", 
 5), even
 though, in the former case, 5 does not match "%s" and "foo" does not match 
 "%d".
 That is, the order of the arguments (or, if you prefer to think that way, 
 the
 order of the types of format strings) does not matter.

 The ? in the title about whether this is a bug in std.format.doFormat 
 comes from
 me not being sure whether the bug lies there or not, but since both the 
 writef
 functions and std.string.format() use doFormat() internally (I looked at 
 the
 Phobos source that much) I presume that's where the problem lies.

 Of course this could be a bug in the documentation: there it is said that
 "[m]ismatched arguments and formats result in a FormatError being thrown." 
 Some
 cases in the above example certainly seem mismatched to me, yet nothing 
 was
 thrown. It may be this is meant to happen (which I doubt, it just doesn't 
 make
 sense), in which case the documentation needs to be corrected.

This might actually be "expected" behavior, as evidenced by these lines from the unittest in std.format: s = std.string.format("hello world! %s %s ", true, 57, 1_000_000_000, 'x', " foo"); assert(s == "hello world! true 57 1000000000x foo"); ??? What a weird way to go about it. It might not technically be a bug, but it sure is confusing and counterintuitive.
Feb 11 2006
parent Chris Sauls <ibisbasenji gmail.com> writes:
Jarrett Billingsley wrote:
 "Deewiant" <deewiant.doesnotlike.spam gmail.com> wrote in message 
 news:dsljv8$2r8b$1 digitaldaemon.com...
 
Note how the format string doesn't change but the order of the arguments 
does:

--
import std.string, std.stdio;

void main() {
printf("%s %d\n", toStringz("foo"), 5); // "foo 5"

// printf("%s %d", 5, toStringz("foo")); // access violation

writefln("%s %d", "foo", 5); // "foo 5"

writefln("%s %d", 5, "foo"); // "5 foo"??

char[] s = format("%s %d", "foo", 5);
writefln(s); // "foo 5"

s = format("%s %d", 5, "foo");
writefln(s); // "5 foo"??
}
--

Or, to clarify:

When using printf(), if the arguments do not match the format string 
exactly,
_including their order_, an access violation occurs.

When using writef(), or std.string.format(), one can pass ("%s %d", 5, 
"foo")
and get the same result as from ("%d %s", 5, "foo") or ("%s %d", "foo", 
5), even
though, in the former case, 5 does not match "%s" and "foo" does not match 
"%d".
That is, the order of the arguments (or, if you prefer to think that way, 
the
order of the types of format strings) does not matter.

The ? in the title about whether this is a bug in std.format.doFormat 
comes from
me not being sure whether the bug lies there or not, but since both the 
writef
functions and std.string.format() use doFormat() internally (I looked at 
the
Phobos source that much) I presume that's where the problem lies.

Of course this could be a bug in the documentation: there it is said that
"[m]ismatched arguments and formats result in a FormatError being thrown." 
Some
cases in the above example certainly seem mismatched to me, yet nothing 
was
thrown. It may be this is meant to happen (which I doubt, it just doesn't 
make
sense), in which case the documentation needs to be corrected.

This might actually be "expected" behavior, as evidenced by these lines from the unittest in std.format: s = std.string.format("hello world! %s %s ", true, 57, 1_000_000_000, 'x', " foo"); assert(s == "hello world! true 57 1000000000x foo"); ??? What a weird way to go about it. It might not technically be a bug, but it sure is confusing and counterintuitive.

I would actually argue its a bug (or symptom of incomplete implementation?) in that the specifier given ("%d") expects an integral type (or else one representable as an integral, such as a real or a class with an opCast to integral), but it accepted a string. I would have expected a FormatException to be thrown. -- Chris Nicholson-Sauls
Feb 12 2006
prev sibling next sibling parent reply "Derek Parnell" <derek psych.ward> writes:
On Sun, 12 Feb 2006 08:12:06 +1100, Deewiant  
<deewiant.doesnotlike.spam gmail.com> wrote:


[snip]

 It may be this is meant to happen (which I doubt, it just doesn't make
 sense), in which case the documentation needs to be corrected.

There is a BIG difference between the C printf and D's Format. In D, the format codes only describe what format to output the data in, it does not use the format codes to describe what data to expect, as printf does. This is because Format is type-safe in that it knows what datatypes it has been given so all it has to do is format it according to your requests (in the format codes used). Thus ... format("%s is the number %s", 5, "five"); is perfectly ok. You have asked it to output (format) the first parameter as a string (%s) and the second parameter as a string too. In fact, as everyting comes out as a string eventually, you only really need the specialist format codes when doing non-default toString conversions, eg. %5.2f for floating point numbers, or %06d to give you a six-character, left-zeroed integer format, etc... -- Derek Parnell Melbourne, Australia
Feb 11 2006
parent Deewiant <deewiant.doesnotlike.spam gmail.com> writes:
Derek Parnell wrote:
 Thus ...
 
     format("%s is the number %s", 5, "five");
 
 is perfectly ok. You have asked it to output (format) the first
 parameter as a string (%s) and the second parameter as a string too. In
 fact, as everyting comes out as a string eventually, you only really
 need the specialist format codes when doing non-default toString
 conversions, eg. %5.2f for floating point numbers, or %06d to give you a
 six-character, left-zeroed integer format, etc...
 
 --Derek Parnell
 Melbourne, Australia

Okay, I can see how it makes sense for strings. But what about something like this: writefln("\"%6d\" is the floating point number \"%3.2f\"", "hello", "hello"); Which spits out '" hello" is the floating point number " he"'. Formatting a string according to how many digits should be after its decimal point seems confusing, to say the least.
Feb 12 2006
prev sibling parent "Walter Bright" <newshound digitalmars.com> writes:
A %s format will take any argument type, and print it as a string. This is 
so that one can do formats without needing to know the type of the argument.

%d means format it as a decimal string. A string argument shouldn't print as 
a decimal, so format() should throw a FormatError exception on this one. 
Feb 14 2006