Thread overview
Bug in std.format.doFormat?
Feb 11, 2006
Deewiant
Feb 13, 2006
Chris Sauls
Feb 11, 2006
Derek Parnell
Feb 12, 2006
Deewiant
Feb 15, 2006
Walter Bright
February 11, 2006
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.
February 11, 2006
"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.


February 11, 2006
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
February 12, 2006
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.
February 13, 2006
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
February 15, 2006
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.