October 09, 2001
EvilOne wrote:

> It would be even better if there's a standartized format string, so it could be generated by D compiler itself by just looking at argument list. So, you can type:
>
>     char c; char[] s;
>     printf(5, c, s);    // format string will _automatically_ be "%d %c %s"

But then, how would you get it to call
   printf("value of foo.bar.baz %d\n", foo.bar.baz);
?

Anyhow, the compiler has all the information it needs to inline as much as it wants.  It is perfectly conceivable that the compiler could inline the whole printf function, determine that there is a problem (and printf will throw an Exception) and so the compiler could throw a warning.

--
The Villagers are Online! http://villagersonline.com

.[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
.[ (a version.of(English).(precise.more)) is(possible) ]
?[ you want.to(help(develop(it))) ]


October 10, 2001
"Russ Lewis" <spamhole-2001-07-16@deming-os.org> wrote in message news:3BC31DC4.83500116@deming-os.org...
> EvilOne wrote:
>
> > It would be even better if there's a standartized format string, so it could be generated by D compiler itself by just looking at argument list. So, you can type:
> >
> >     char c; char[] s;
> >     printf(5, c, s);    // format string will _automatically_ be "%d %c %s"
>
> But then, how would you get it to call
>    printf("value of foo.bar.baz %d\n", foo.bar.baz);

printf("value of foo.bar.baz ", foo.bar.baz, "\n");

But of course, this is not printf(). So maybe call it print() or writeln()?
Anyhow, I believe that such syntax is much clearer than of C-style printf().
Since there's no operator overloading in D, it's not possible to implement
C++ iostreams with their intuitive usage of << and >>. But there must be
a _simple_ way to perform at least console input and output. printf() is
not the best choice here, imho.


October 10, 2001
Hello,

Please excuse me for intruding, but I too have been thinking along the line of the EvilOne, that:

	printf(5, c, s, someObj);
should internally call:
	printf( 5.toString(), c.toString(), s.toString(), someObj.toString() );

where the toString() will provide the default formatting.

If one wants different formatting, than that object should override the only other toString function from the base Object class:

	String toString(String fmt);

so now we can have:
	printf ( 5, c, s, someObj("-5x") ); // prefer this syntax
or
	printf ( 5, c, s, someObj.toString("-5x") ); // ... over this

I would rather have two functions print & println instead of printf, but thats besides my point.

Also, to fix the vaarg problem, if the syntax
	{x, y, z}
creates a collection initialized with the objects x, y, z; then this
should work:
	println( { x, y ,z } );
or
	println( { "value of foo is", foo("-9.5f") } );

Anyway, just my 2c.

- nik.

EvilOne wrote:
> 
> "Russ Lewis" <spamhole-2001-07-16@deming-os.org> wrote in message news:3BC31DC4.83500116@deming-os.org...
> > EvilOne wrote:
> >
> > > It would be even better if there's a standartized format string, so it could be generated by D compiler itself by just looking at argument list. So, you can type:
> > >
> > >     char c; char[] s;
> > >     printf(5, c, s);    // format string will _automatically_ be "%d %c %s"
> >
> > But then, how would you get it to call
> >    printf("value of foo.bar.baz %d\n", foo.bar.baz);
> 
> printf("value of foo.bar.baz ", foo.bar.baz, "\n");
> 
> But of course, this is not printf(). So maybe call it print() or writeln()?
> Anyhow, I believe that such syntax is much clearer than of C-style printf().
> Since there's no operator overloading in D, it's not possible to implement
> C++ iostreams with their intuitive usage of << and >>. But there must be
> a _simple_ way to perform at least console input and output. printf() is
> not the best choice here, imho.
October 10, 2001
EvilOne wrote:

> printf("value of foo.bar.baz ", foo.bar.baz, "\n");
>
> But of course, this is not printf(). So maybe call it print() or writeln()?
> Anyhow, I believe that such syntax is much clearer than of C-style printf().

I see your point, and it's valid to think that it's clearer.  I disagree :)  For simplistic printing, cout has some real advantages.  But for complex ones, it really gets weak:

printf("value of my variable: %.8x\n",
        foo->GetOrthogonalBaz()
               ->Barrify()
               ->GetNormal(1,2,3)
               ->MakeHorizontal(false)
               ->GetX());

I would challenge anyone here to write the cout code that matches the formatting capabilities of printf.  I would also challenge anybody to write cout code that expresses, as clearly as the printf format string, how the stuff will actually look on the screen.

IMHO, printf shines where you need complex formatting and/or the arguments are complex.

> Since there's no operator overloading in D, it's not possible to implement C++ iostreams with their intuitive usage of << and >>. But there must be a _simple_ way to perform at least console input and output. printf() is not the best choice here, imho.

Fair enough.  I like << and >> primarily because of their type-safety (scanf is HORRID).  However, there is a lot of elegance to the code:

int i;
cin >> i;

Which is more visual than

int i;
scanf("%d",&i);

Or, what I normally end up doing because I can never remember how scanf works:

int i;
char buf[32];
fgets(buf,32,stdin);
i = atoi(buf);

--
The Villagers are Online! villagersonline.com

.[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
.[ (a version.of(English).(precise.more)) is(possible) ]
?[ you want.to(help(develop(it))) ]


October 10, 2001
Russ Lewis wrote:
> 
> EvilOne wrote:
> 
> > printf("value of foo.bar.baz ", foo.bar.baz, "\n");
> >
> > But of course, this is not printf(). So maybe call it print() or writeln()?
> > Anyhow, I believe that such syntax is much clearer than of C-style printf().
> 
> I see your point, and it's valid to think that it's clearer.  I disagree :)  For simplistic printing, cout has some real advantages.  But for complex ones, it really gets weak:
> 
> printf("value of my variable: %.8x\n",
>         foo->GetOrthogonalBaz()
>                ->Barrify()
>                ->GetNormal(1,2,3)
>                ->MakeHorizontal(false)
>                ->GetX());
> 
> I would challenge anyone here to write the cout code that matches the formatting capabilities of printf.

	cout << "value of my variable: "
	     << setw(8) << hex
	     << foo->GetOrthogonalBaz()
			->Barrify()
			->GetNormal(1,2,3)
			->MakeHorizontal(false)
			->GetX()
	     << endl;

> I
> would also challenge anybody to write cout code that expresses, as clearly as the printf format string, how
> the stuff will actually look on the screen.

	I don't think the above is all that bad really.  As far as clearness,
I've never though all the %magic was really that clear.  It's ugly as
sin to tell the truth.  Of course if you want things to appear in the
code as they would on the screen, we could go back to COBOL picture
statements.  Perl has a similar feature that they are about to rip out
of the perl core.
	I'm not against having something like printf in D, but I have two
issues.  It is real nice to be able to define input and output routines
for user defined types that can be used with the standard I/O code,
since some user types are simply made to make up for the deficiencies in
the language's built-ins.  (Dates, vectors, etc.)  The other is that
printf can be a huge security hole.  You may challenge people write cout
code that you think is pretty.  I challenge anyone to implement a printf
that isn't capable of producing security breaches.  (I'm looking at the
format string when I say that.)

> IMHO, printf shines where you need complex formatting and/or the arguments are complex.

And the beauty of iostreams is that you can write code so that even the
most complex types can be read or written as easily as a simple infix
expression.

> Fair enough.  I like << and >> primarily because of their type-safety (scanf is HORRID).  However, there is a lot of elegance to the code:
> 
> int i;
> cin >> i;
> 
> Which is more visual than
> 
> int i;
> scanf("%d",&i);
> 
> Or, what I normally end up doing because I can never remember how scanf works:
> 
> int i;
> char buf[32];
> fgets(buf,32,stdin);
> i = atoi(buf);

scanf is horrid, but printf isn't?  They are the left and right arms of the same depraved beast.

Dan
October 10, 2001
a wrote:

> > printf("value of my variable: %.8x\n",
> >         foo->GetOrthogonalBaz()
> >                ->Barrify()
> >                ->GetNormal(1,2,3)
> >                ->MakeHorizontal(false)
> >                ->GetX());
> >
> > I would challenge anyone here to write the cout code that matches the formatting capabilities of printf.
>
>         cout << "value of my variable: "
>              << setw(8) << hex
>              << foo->GetOrthogonalBaz()
>                         ->Barrify()
>                         ->GetNormal(1,2,3)
>                         ->MakeHorizontal(false)
>                         ->GetX()
>              << endl;

clap,clap,clap.  I couldn't have done that.  One question...doesn't the "hex" format persist?  Shouldn't you reset that somehow, so that it doesn't corrupt later print on cout?  Or does it reset after printing one thing?

> > I
> > would also challenge anybody to write cout code that expresses, as clearly as the printf format string, how
> > the stuff will actually look on the screen.
>
>         I don't think the above is all that bad really.  As far as clearness,
> I've never though all the %magic was really that clear.  It's ugly as
> sin to tell the truth.  Of course if you want things to appear in the
> code as they would on the screen, we could go back to COBOL picture
> statements.  Perl has a similar feature that they are about to rip out
> of the perl core.

True, %magic is ugly, but I haven't seen better yet.  I don't know anything about COBOL, so I can't really speak to it...

>         I'm not against having something like printf in D, but I have two
> issues.  It is real nice to be able to define input and output routines
> for user defined types that can be used with the standard I/O code,
> since some user types are simply made to make up for the deficiencies in
> the language's built-ins.  (Dates, vectors, etc.)

True, this is nice.  Maybe functions of the base class ('object', I think it was) that you can override.

> The other is that
> printf can be a huge security hole.  You may challenge people write cout
> code that you think is pretty.  I challenge anyone to implement a printf
> that isn't capable of producing security breaches.  (I'm looking at the
> format string when I say that.)

I've heard of such things...things like the ability to read memory directly and such.  Can you give examples of it, since I haven't seen it firsthand?

I thought that printf in general...where one %magic correlates to one argument, and there are none of the special specifires...was secure, even if all of the extensions of it are not.  Am I wrong?  (p.s. I know that sprintf can cause buffer overflows...but other than that...)

> scanf is horrid, but printf isn't?  They are the left and right arms of the same depraved beast.

I don't think that that's fair.  To me, it seems that printf was designed to allow flexible printing syntax.  As long as you don't mix the wrong formatter with the wrong type, you're ok...and were looking to see if there's a way to make a D version of printf that is typesafe so you can't use the wrong formatter.

It appears to me that scanf was designed to look like printf...but in doing so, it created a nightmare.  scanf should have been designed very differently, in a way that made sense for reading, just like printf was designed to work well with output.

Anyhow, this is all just my opinion.  I use both cout and printf as my whims dictate :)

--
The Villagers are Online! villagersonline.com

.[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
.[ (a version.of(English).(precise.more)) is(possible) ]
?[ you want.to(help(develop(it))) ]


October 10, 2001
> Anyhow, this is all just my opinion.  I use both cout and printf as my whims dictate :)

The question is, what we'll have in D?


October 10, 2001
Russ Lewis wrote:
> 
> a wrote:
> >
> >         cout << "value of my variable: "
> >              << setw(8) << hex
> >              << foo->GetOrthogonalBaz()
> >                         ->Barrify()
> >                         ->GetNormal(1,2,3)
> >                         ->MakeHorizontal(false)
> >                         ->GetX()
> >              << endl;
> 
> clap,clap,clap.  I couldn't have done that.  One question...doesn't the "hex" format persist?  Shouldn't you reset that somehow, so that it doesn't corrupt later print on cout?  Or does it reset after printing one thing?

	You got me.  I tried to convince myself that hex worked like setw() and
a number of the other one shot manipulators.  It kind of sucks in this
case.  You would have to save the state flag before the cout and restore
it when you're done doing hex.

> True, %magic is ugly, but I haven't seen better yet.  I don't know anything about COBOL, so I can't really speak to it...

	Oh, you missed out.  You define a format line that specifies who field
will be laid out.  Then when you print you give it the format name a a
list variables (a record actually that you've populated with the data).

> >         I'm not against having something like printf in D, but I have two
> > issues.  It is real nice to be able to define input and output routines
> > for user defined types that can be used with the standard I/O code,
> > since some user types are simply made to make up for the deficiencies in
> > the language's built-ins.  (Dates, vectors, etc.)
> 
> True, this is nice.  Maybe functions of the base class ('object', I think it was) that you can override.

You still need to create your own %magic symbol to use it with printf,
so he knows how to handle the argument.  That just make the % problem
worse, if not open ended.  I admit that printf does what it does better
that most anything else.  It's just not capable of being expanded in a
reasonable way.

> > The other is that
> > printf can be a huge security hole.  You may challenge people write cout
> > code that you think is pretty.  I challenge anyone to implement a printf
> > that isn't capable of producing security breaches.  (I'm looking at the
> > format string when I say that.)
> 
> I've heard of such things...things like the ability to read memory directly and such.  Can you give examples of it, since I haven't seen it firsthand?

Not on short notice.  :-)

> I thought that printf in general...where one %magic correlates to one argument, and there are none of the special specifires...was secure, even if all of the extensions of it are not.  Am I wrong?  (p.s. I know that sprintf can cause buffer overflows...but other than that...)
> 
> > scanf is horrid, but printf isn't?  They are the left and right arms of the same depraved beast.
> 
> I don't think that that's fair.

Well I am trying to vilify stdio after all...

>To me, it seems that printf was designed to allow flexible printing syntax.  As
> long as you don't mix the wrong formatter with the wrong type, you're ok...and were looking to see if there's a way to make a D version of printf that is typesafe so you can't use the wrong formatter.

	If it's type safe, then you don't need the formatter in most cases.
The %i, %d, %s, %c, %x, etc. formats are redundant if printf could be
made type safe.  They would allow you to put an implicit case of some
sort in the format string, but that sounds nasty to me.  And it defies
the "Only one way to possibly do it." ideology that D seems to be going
for.  (Maybe I do like it.)
	Maybe we could define a function that takes a list of class printable
objects (and class Object could have a cast defined that users could
override) and then we could allow optional modifiers to be applied to
the arguments.  There is no point in forcing some to specify formats
when all he wants say is:
	print("It was: ", it, "\n");


> It appears to me that scanf was designed to look like printf...but in doing so, it created a nightmare.  scanf should have been designed very differently, in a way that made sense for reading, just like printf was designed to work well with output.

printf allows aggregate printing. scanf allow aggregate reading.  I used
to work with folks who loved scanf the way you love printf.  Both are
better than the world of have a read and print function for every data
type imaginable for the user to memorize the options to.  It's just that
it feels like it is time to get fed up and improve things again.

> Anyhow, this is all just my opinion.  I use both cout and printf as my whims dictate :)

	Same here.  Recently I began to force myself to use cout even when it
hurts so I can learn how to criticize it more meaningfully.  It ain't
printf but it's not as bad as most people make it out to be.  It's cool
that you can make your own custom manipulators easily, but it would be
nicer if you could define a manipulator type and assign it the
OR/accumulation/whatever a bunch of manipulations together so you could
then apply it to a variable being inserted.

	form F = hex + width(5) + center;
	cout << x << F + y << width(3) + right + z << endl;

It still needs work, but it give the basic idea.  I just used plus every where because I was at a loss for words.  The accumulation operator should be different from the apply operator.  Maybe it could be spelled:

	form F = hex & width(5) & center;
	cout << x << F|y << width(3)&right|z << end;

It might be nice to be apply to apply to a list of arguments too. But I digress.  This type of syntax won't work for D.

Dan
October 10, 2001
a wrote:

> > >         I'm not against having something like printf in D, but I have two
> > > issues.  It is real nice to be able to define input and output routines
> > > for user defined types that can be used with the standard I/O code,
> > > since some user types are simply made to make up for the deficiencies in
> > > the language's built-ins.  (Dates, vectors, etc.)
> >
> > True, this is nice.  Maybe functions of the base class ('object', I think it was) that you can override.
>
> You still need to create your own %magic symbol to use it with printf, so he knows how to handle the argument.  That just make the % problem worse, if not open ended.  I admit that printf does what it does better that most anything else.  It's just not capable of being expanded in a reasonable way.

How about:

class object     // base for everything else
{
public:
   char[] toString() { // default value returns a hex print of the 'this' pointer };
};

The implementation recognizes a new %magic that is only legal when matched to an argument that is a pointer to object (or
a child, ofc).  Any classes that want to override how they are printed must override toString().  Thus, you only add 1
%magic that will work with all classes.

It doesn't help with structs, ofc...

> > > scanf is horrid, but printf isn't?  They are the left and right arms of the same depraved beast.
> >
> > I don't think that that's fair.
>
> Well I am trying to vilify stdio after all...

LOL

>         If it's type safe, then you don't need the formatter in most cases.
> The %i, %d, %s, %c, %x, etc. formats are redundant if printf could be
> made type safe.  They would allow you to put an implicit case of some
> sort in the format string, but that sounds nasty to me.  And it defies
> the "Only one way to possibly do it." ideology that D seems to be going
> for.  (Maybe I do like it.)

Hold on here...the point of those specifiers is to tell you how to print something.  %d (and %i, which I think is identical) prints an integer in decimal format.  %c prints the ASCII character that has the ASCII code given.  %x and %X are two distinct ways of printing an integer as a hexdecimal value.  All of these specifiers can work on the SAME argument!

printf("%d %c %x %X",10,10,10,10);
  prints out
"10 \n a A"

The typesafety comes in when you try to pass a char[] and print it as an integer, or an integer and you try to print it as a string (meaning printf expects it to be a pointer value).  In either of those cases, printf() would throw an exception.

> > It appears to me that scanf was designed to look like printf...but in doing so, it created a nightmare.  scanf should have been designed very differently, in a way that made sense for reading, just like printf was designed to work well with output.
>
> printf allows aggregate printing. scanf allow aggregate reading.  I used to work with folks who loved scanf the way you love printf.  Both are better than the world of have a read and print function for every data type imaginable for the user to memorize the options to.  It's just that it feels like it is time to get fed up and improve things again.

I suppose scanf might work to my liking, if it was typesafe, wouldn't overrun buffers, and didn't require you to take the
address of every little integer you're reading.

I agree, it's time for an upgrade.  cout might be a step in the right direction, but I think it's more of a step sideways.  Let's brainstorm... :)

> > Anyhow, this is all just my opinion.  I use both cout and printf as my whims dictate :)
>
>         Same here.  Recently I began to force myself to use cout even when it
> hurts so I can learn how to criticize it more meaningfully.  It ain't
> printf but it's not as bad as most people make it out to be.  It's cool
> that you can make your own custom manipulators easily, but it would be
> nicer if you could define a manipulator type and assign it the
> OR/accumulation/whatever a bunch of manipulations together so you could
> then apply it to a variable being inserted.
>
>         form F = hex + width(5) + center;
>         cout << x << F + y << width(3) + right + z << endl;
>
> It still needs work, but it give the basic idea.  I just used plus every where because I was at a loss for words.  The accumulation operator should be different from the apply operator.  Maybe it could be spelled:
>
>         form F = hex & width(5) & center;
>         cout << x << F|y << width(3)&right|z << end;
>
> It might be nice to be apply to apply to a list of arguments too. But I digress.  This type of syntax won't work for D.

I actually kind of like your syntax, personally.  It has the potential for the compactness I like of printf with the all of the OOP benefits.

And it's actually not as far from D syntax as you might think.  What if we make some definitions:

class FormElement;
typedef FormElement[] form;

form hex = { hexElement };
form width(int i) { return ... };
form center = { centerElement };

To accumulate types, you do this:

form F = hex + width(5) + center;

which D interprets as concatenating arrays.  Now walter helps us by adding a property function called "format" which takes a form argument and returns a char[].  We also implement it as a function in 'object', so now we can print easily:

stdout.print(x.format() + "this is a string" + y.format(F) + z.format(width(3)+right) + endl);

Thoughts?

--
The Villagers are Online! villagersonline.com

.[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
.[ (a version.of(English).(precise.more)) is(possible) ]
?[ you want.to(help(develop(it))) ]


October 11, 2001
"Russ Lewis" <spamhole-2001-07-16@deming-os.org> wrote in message news:3BC477F3.F4D0452C@deming-os.org...

> printf("value of my variable: %.8x\n",
>         foo->GetOrthogonalBaz()
>                ->Barrify()
>                ->GetNormal(1,2,3)
>                ->MakeHorizontal(false)
>                ->GetX());
>
> I would challenge anyone here to write the cout code that matches the
formatting capabilities of printf.  I
> would also challenge anybody to write cout code that expresses, as clearly
as the printf format string, how
> the stuff will actually look on the screen.
>
> IMHO, printf shines where you need complex formatting and/or the arguments
are complex.


You are right!  As it is said in the FAQ printf is damned useful.

It also allows you to reuse those format strings again and again without having to use common routines to build up the messages.

In fact I have worked with code that goes further down the format string road than printf, and would be impossible to do with C++ iostreams or string concatenation. When you do internationalisation you often need to be able to re-order where the arguments appear within the format.

In your code you may put:
    display(getMessage(201), colour, item);
in you English message file you may put:
    201="You have selected a |0 |1."
but in other languages you might need to name the item before giving its
colour, so the message file might appear:
    201="You have selected a |1, |0."                // sorry I'm
uni-lingual.

However, I understand the frustration at printf.  I have seen well tested software crash in live situations because printf had the wrong number of arguments and the program has segmented.  You might say it cannot be well tested if it crashes, but most of the messages in a C program are there to deal with errors that will probably never happen.  It is very difficult and unproductive to exercise all the error handling code.  So where the compiler can check the format string against the arguments, I say please let it (I believe gcc does this with the -Wformat option).

Unfortunately taking the messages out of the code (as above) and putting them into files would stop any attempt by the compiler to check the format string against parameter types.  Where the compiler cannot see the format string, then I afraid it is upto the programmer to eyeball his code, or write tools to do this checking.

I have written my own tools that parse the C sources and associated format strings, and then creates copies of the source with the printf function name replaced with one that mangles in the expected parameter types, and adds a related prototype.  Compiling these copies flushes out the type errors.