D - variable number of arguments
- EvilOne (3/3) Oct 04 2001 Is there support for variable number of arguments in D? Something
- a (7/11) Oct 04 2001 printf is supported. I would guess that something like C's varargs will
- Walter (3/12) Oct 05 2001 D will support variable arguments, but only in interfacing to C function...
- pontus (9/9) Oct 07 2001 SGVsbG8NCg0KSW4gYSBnZW5lcmFsIHdheSwgY291bGRuJ3QgaXQgYmUgc29sdmVkIGxpa2Ug
- Walter (11/11) Oct 07 2001 The problem is that arguments on the stack can be different sizes.
- Pontus Pihlgren (3/20) Oct 08 2001 Well,maybe i'm missing something, but with a string and an array of
- Axel Kittenberger (20/20) Oct 08 2001 Pontus Pihlgren wrote:
- Walter (10/10) Oct 08 2001 Given:
- Russ Lewis (40/40) Oct 09 2001 What were your (Walter's) thoughts about the recursive scheme I cooked u...
- EvilOne (7/10) Oct 09 2001 [...]
- Russ Lewis (12/17) Oct 09 2001 But then, how would you get it to call
- EvilOne (8/17) Oct 10 2001 printf("value of foo.bar.baz ", foo.bar.baz, "\n");
- nik (26/48) Oct 10 2001 Hello,
- Russ Lewis (30/37) Oct 10 2001 I see your point, and it's valid to think that it's clearer. I disagree...
- a (31/71) Oct 10 2001 cout << "value of my variable: "
- Russ Lewis (23/60) Oct 10 2001 clap,clap,clap. I couldn't have done that. One question...doesn't the ...
- EvilOne (1/2) Oct 10 2001 The question is, what we'll have in D?
- a (55/101) Oct 10 2001 You got me. I tried to convince myself that hex worked like setw() and
- Russ Lewis (45/93) Oct 10 2001 How about:
- a (61/160) Oct 13 2001 Well, at the very least, I'd like to have a toStream method that can
- Russ Lewis (15/59) Oct 13 2001 What if toString had a char[] argument:
- a (52/117) Oct 13 2001 I like this idea. I still don't like %magic, but this improves it a
- Russ Lewis (48/79) Oct 14 2001 The key with strong typing is that you know what you know and you don't ...
- a (62/133) Oct 19 2001 Well are typesafe in that it will always be a descendant of Object.
- Russ Lewis (26/82) Oct 19 2001 Remember that all member functions of classes are automatically virtual ...
- Sean L. Palmer (22/48) Nov 04 2001 I hope the hell somebody goes through D and standardizes capitalization
- a (24/80) Nov 04 2001 The only problem is you have to make sure no character conversion
- Charles Hixson (19/19) Oct 17 2001 Are you implying that .toString() is a "magic method" that will
- Russ Lewis (14/16) Oct 17 2001 We have been using the term "magic" to refer to the printf format
- Reg Whitton (37/47) Oct 11 2001 formatting capabilities of printf. I
Is there support for variable number of arguments in D? Something like VB's ParamArray, or maybe another (better?) way... or is this something that's not going to be the language feature?
Oct 04 2001
EvilOne wrote:Is there support for variable number of arguments in D? Something like VB's ParamArray, or maybe another (better?) way... or is this something that's not going to be the language feature?printf is supported. I would guess that something like C's varargs will be supported. It's a shame that useful (in my mind) features can be dropped because that are dangerous, but we keep C's varargs (and printf for that matter). (I guess this is assuming that varargs must be supported for printf) Doesn't var-args rely on macros? Dan
Oct 04 2001
a wrote in message <3BBD3952.29C9B2A4 b.c>...EvilOne wrote:D will support variable arguments, but only in interfacing to C functions. It's only real use is for printf(), etc.Is there support for variable number of arguments in D? Something like VB's ParamArray, or maybe another (better?) way... or is this something that's not going to be the language feature?printf is supported. I would guess that something like C's varargs will be supported. It's a shame that useful (in my mind) features can be dropped because that are dangerous, but we keep C's varargs (and printf for that matter). (I guess this is assuming that varargs must be supported for printf) Doesn't var-args rely on macros?
Oct 05 2001
SGVsbG8NCg0KSW4gYSBnZW5lcmFsIHdheSwgY291bGRuJ3QgaXQgYmUgc29sdmVkIGxpa2Ug dGhpczoNCg0Kdm9pZCBwcmludGYoImZvcm1hdCBzdHJpbmciLCAqdm9pZFtdKTsNCg0KVGhh dCBpcyBhbiBhcnJheSB3aXRoIHBvaW50ZXJzKGhvcGUgaSBnb3QgdGhlIHN5bnRheCByaWdo dCkuIEFuZCBzaW5jZSBhcnJheQ0KbGVuZ2h0cyBhcmUgYSBwcm9wZXJ0eSBvZiBhcnJheSB0 aGlzIHdvdWxkIGJlIGFuIGVhc3kgdGhpbmcgdG8gaW1wbGVtZW50Lg0KQSBvYnZpb3VzIHBy b2JsZW0gdGhvdWdoLCBpcyBob3cgd291bGQgeW91IGtub3cgdGhhdCB0aGUgdGhpbmcgcG9p bnRlZCB0byBhdA0KcGxhY2UgbiBpcyB0aGUgc2FtZSB0eXBlIGFzIGVudGl0eSBuIGluIHRo ZSBmb3JtYXQgc3RyaW5nLCBidXQgZnJvbSB3aGF0IEkNCmNhbiBzZWUgdGhhdCBpcyBhIHBy b2JsZW0gd2l0aCB2YXIgYXJncyB0by4NCg0KL1BvbnR1cw0K
Oct 07 2001
The problem is that arguments on the stack can be different sizes. pontus wrote in message <3BC071D5.D574F0AC student.uu.se>... Hello In a general way, couldn't it be solved like this: void printf("format string", *void[]); That is an array with pointers(hope i got the syntax right). And since array lenghts are a property of array this would be an easy thing to implement. A obvious problem though, is how would you know that the thing pointed to at place n is the same type as entity n in the format string, but from what I can see that is a problem with var args to. /Pontus
Oct 07 2001
Well,maybe i'm missing something, but with a string and an array of pointers, what on the stack have diffrent size? Walter wrote:The problem is that arguments on the stack can be different sizes. pontus wrote in message <3BC071D5.D574F0AC student.uu.se>...Hello In a general way, couldn't it be solved like this: void printf("format string", *void[]); That is an array with pointers(hope i got the syntax right). And since array lenghts are a property of array this would be an easy thing to implement. A obvious problem though, is how would you know that the thing pointed to at place n is the same type as entity n in the format string, but from what I can see that is a problem with var args to. /Pontus
Oct 08 2001
Pontus Pihlgren wrote: void myfunc(char a, char b, char); will possibly put something like this on stack: +--+--+--+ | a | b | c | +--+--+--+ where a, b and c is only one byte long. Today on almost all 32bit processesor (void *) ist 4 byte long so *void[3] will look like this +-----------+-----------+-----------+ | *void[0] | *void[1] | *void[2] | +-----------+-----------+-----------+ each element is 4 bytes wide, see the difference? and why (void *) can most times not be used to track function arguments. It is only possible if the compiler always puts 4 bytes on stack for every argument even smaller ones, and of course also never bigger ones like 'long long', but this might be profuseness, however honestly I've no idea how compilers do today... or how printf("%c%c%c", a, b, c); will be placed on stack for an x86 processsor, maybe it uses 4 byte frames after all, in which case a (void **) could actually function...
Oct 08 2001
Given: printf(" ... ", char, int, long long, double, long double); the compiler pushes on the stack: char 4 int 4 long long 8 double 8 ld 12 and in general any struct can be passed by value, and can be any (aligned) size. Every scheme I've come up with to deal with this is inefficient.
Oct 08 2001
What were your (Walter's) thoughts about the recursive scheme I cooked up? I remember other people commented on it, but I don't remember you speaking about it. D code: char[] printf(char[],....) // declares that variable argument lists are ok, no body may be defined out(result) { assert(result == ""); }; char[] printf(char[],char) {...}; char[] printf(char[],int) {...}; char[] printf(char[],char[]) {...}; char[] printf(char[],void*) {...}; Each version of printf accepts as its first argument the format string. It will throw an exception if the format specifier is invalid for the type. Otherwise, it does the printing and returns any remaining portion of the format string. The compiler expands the variable argument call inline: D call: char c; char[] s; int i; printf("%c %s %d",c,s,i); Expands to: char c; char[] s; int i; printf(printf(printf("%c %s %d",c),s),i); None of which are variable argument fucntion calls, and all of which are typesafe. The innermost printf returns the string "%s %d", while the next returns "%d", while the last returns "". Only then is the out condition checked; it is fine, so the program goes on. Note that this requires that the 1st argument of the call be the same type as the return type; anything else would be a syntax error in this scheme. To allow multiple fixed arguments, the format is similar: int foo(int, // recursive argument char,void*,char[], // these arguments are all called the same to all copies of the recursion. ....); // variable argument. -- 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))) ]
Oct 09 2001
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message news:3BC2A336.74A74409 deming-os.org...What were your (Walter's) thoughts about the recursive scheme I cooked up? I remember other people commented on it, but I don't remember you speaking about it.[...] 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"
Oct 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))) ]
Oct 09 2001
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message news:3BC31DC4.83500116 deming-os.org...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(). 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.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);
Oct 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: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.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);
Oct 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))) ]
Oct 10 2001
Russ Lewis wrote:EvilOne wrote:cout << "value of my variable: " << setw(8) << hex << foo->GetOrthogonalBaz() ->Barrify() ->GetNormal(1,2,3) ->MakeHorizontal(false) ->GetX() << endl;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.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
Oct 10 2001
a wrote: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?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;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 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.)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))) ]
Oct 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?
Oct 10 2001
Russ Lewis wrote:a wrote: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.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?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).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.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.Not on short notice. :-)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...)Well I am trying to vilify stdio after all...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.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
Oct 10 2001
a wrote: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...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.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.LOLWell I am trying to vilify stdio after all...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.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.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... :)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 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))) ]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.
Oct 10 2001
Russ Lewis wrote:a wrote:Well, at the very least, I'd like to have a toStream method that can default to toString. The human readable format is not always the best/most complete way to store to a file. Given only one %magic symbol that can handle all descendants of Object would work, but you would only have one way of formatting, and how would you deal with the %modifiers? (Assuming we really want the kludge up printf this way.)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...You are right that there is a difference between %d and %x (etc.) that we'd need to keep. In the above discussion, we could not have such differences in representation for objects. A pity. I will argue that you don't need %c or similar %magic that specify a type, but not a representation. In your above example, if you want 10 to be a char, cast it. that is the implicit cast I was talking about.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.The whole OO and infix think I think was in at least a vaguely forward direction.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... :)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.Is the array thing really the best way to do this? I looks to me like a hack to get around the lack of operator overloads. It might feel better like: format.apply(hex).apply(right).apply(width(3)); I'm not crazy in love with this either. On an aesthetic level, I think I'm more accustomed to the format coming before the data being formatted. That's minor though. If enough people agree though, we could be the format something that take an argument and returns something streamable. I can say that I don't like the concatenations prior to the print operation. If print could safely do variable arguments, it could print/write them all without having to allocate an intermediate buffer the size of everything being printed and copying it. There would be excess time overhead with the extra copying and memory overhead with the temp string. This isn't a problem with print so much as it's the only way we can pass a variable number of objects to a print routine. Another aesthetic note. Say what you will about cout's failings, I do find the expression based syntax more visually pleasing. It's a style thing I think. I hate doing multi-line method invocations. Multi-line expressions don't for some reason unless it's an argument to function or control structure. In your example I would probably want to do: stdout.print(x.format() + "this is a string" + y.format(F) + z.format(width(3)+right) + endl); For some reason I like it better when it's not a method call. Cout's formatting is still gross in form and function but I find its code formats better for my eyes. I like the example less since those are pluses and not commas. For plain function calls, I don't tend to mind splitting lines on commas. Anything else just feels icky. I know my reasoning here is dippy, but style is like that. I think it would be worth brain storming out how the I/O might work. The same is true of other library like functions. Java got big before it's library was stable. I'm not sure I'd feel safe calling it stable yet. I'd hate to see D follow in Java's foot steps in this way. I've found the difference between versions of java to bother me more than the differences implementations of C on different platforms. It rivals C++. (Granted, I've had the supreme pleasure of not having to code for Windows.) DanSame 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?
Oct 13 2001
a wrote:Russ Lewis wrote:What if toString had a char[] argument: stdout.print("%z %'asdf'z", obj1, obj2); The 'asdf' string would be passed to the toString call on obj2.a wrote:Well, at the very least, I'd like to have a toStream method that can default to toString. The human readable format is not always the best/most complete way to store to a file. Given only one %magic symbol that can handle all descendants of Object would work, but you would only have one way of formatting, and how would you deal with the %modifiers? (Assuming we really want the kludge up printf this way.)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...I will argue that you don't need %c or similar %magic that specify a type, but not a representation. In your above example, if you want 10 to be a char, cast it. that is the implicit cast I was talking about.That's true, kind of. But there is a substantial difference between "print the decimal representation of this byte", "print the hexadecimal representation of this byte", and "print the ASCII representation of this byte", all of which are valid for a char type.Is the array thing really the best way to do this?I certainly hope not!I looks to me like a hack to get around the lack of operator overloads.Very true. It is very ugly; it was just a brainstorm to get things started. :)It might feel better like: format.apply(hex).apply(right).apply(width(3)); I'm not crazy in love with this either. On an aesthetic level, I think I'm more accustomed to the format coming before the data being formatted. That's minor though. If enough people agree though, we could be the format something that take an argument and returns something streamable.char[] format(form,int) ??? -- 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))) ]
Oct 13 2001
Russ Lewis wrote:a wrote:I like this idea. I still don't like %magic, but this improves it a bit. It did just strike me though, we were going after typesafety somewhere back there. By have one %magic for all object, haven't we killed real typesafety? For instance, suppose you passed the wrong object type to your print statement above. It would be valid still. It may barf at runtime because it doesn't handle 'asdf'. Not to derail you, its a good idea, but how do we get typesafety back into it?Russ Lewis wrote:What if toString had a char[] argument: stdout.print("%z %'asdf'z", obj1, obj2); The 'asdf' string would be passed to the toString call on obj2.a wrote:Well, at the very least, I'd like to have a toStream method that can default to toString. The human readable format is not always the best/most complete way to store to a file. Given only one %magic symbol that can handle all descendants of Object would work, but you would only have one way of formatting, and how would you deal with the %modifiers? (Assuming we really want the kludge up printf this way.)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...There a different representations, like hex, oct, dec, left, right, etc. but doesn't %h only work for type char because printf uses varargs converting chars into ints? I'm just used to the bare %magic being used to specify type. That notion should die and be replaced with type safety. Representation descriptors would still be valid, but in many cases a sane default should be acceptable. Make character type look like characters, make numbers look like numbers, etc.I will argue that you don't need %c or similar %magic that specify a type, but not a representation. In your above example, if you want 10 to be a char, cast it. that is the implicit cast I was talking about.That's true, kind of. But there is a substantial difference between "print the decimal representation of this byte", "print the hexadecimal representation of this byte", and "print the ASCII representation of this byte", all of which are valid for a char type.Sorry. :-)Is the array thing really the best way to do this?I certainly hope not!Well, I guess the very first thing we ought to decide what type of syntax we want. If we go all procedural, we are ok. You said you would need a format property in your idea. I think I like that, but I'm not sure how to best leverage it. In any case that is something we would have to be Walter for. Likewise, if we want more on an expression based syntax, we either have to kludge around with the built-in types in D or we have to beg Walter to add a couple more primitives, with operators. At that point I'd say we are work in the language itself though and not in the library.I looks to me like a hack to get around the lack of operator overloads.Very true. It is very ugly; it was just a brainstorm to get things started. :)I'm not sure really. I guess I was thinking: form F = <manipulator(s)>; // custom stdio.print(v1, hex(v2), F(v3)); // default form, hex form, my custom form But think makes it difficult or applets nasty looking to apply multiple format manipulator to a single variable in the print statement. stdio.print(hex(width(3, right(v1)))); // lisp anyone I don't think I would want to have to declare a format type for every custom manipulation. It would give us one of the worst drawbacks of COBOL's and perl's record based output without the benefits. I'm also having trouble being objective coming up with something looks like it fits D's ideology. I'm real partial to C++'s i/o and in D that's right out. I like the suggestion you had above for %magic on object types but I don't think it goes far enough. Would help to work out a formalized set of string ops to build upon? Most I/O will either be binary records or text strings I would assume. The binary output wouldn't need much in the way of formatting. fixed record sizes, byte and bit ordering and that sort of thing should do. It's with the human readable that we worry and justification, representation, padding, text formation of complex types. Maybe we would have a better feel for what feels right for printing strings in D once we get a feel for what it would be like to just muck around with strings in D. DanIt might feel better like: format.apply(hex).apply(right).apply(width(3)); I'm not crazy in love with this either. On an aesthetic level, I think I'm more accustomed to the format coming before the data being formatted. That's minor though. If enough people agree though, we could be the format something that take an argument and returns something streamable.char[] format(form,int) ???
Oct 13 2001
a wrote:I like this idea. I still don't like %magic, but this improves it a bit. It did just strike me though, we were going after typesafety somewhere back there. By have one %magic for all object, haven't we killed real typesafety? For instance, suppose you passed the wrong object type to your print statement above. It would be valid still. It may barf at runtime because it doesn't handle 'asdf'. Not to derail you, its a good idea, but how do we get typesafety back into it?The key with strong typing is that you know what you know and you don't have to make wild guesses or assumptions. When the %z (or whatever) magic is passed, if the typesafe printf sees that the matching argument is anything but a pointer to an object, then it throws an exception. If it is an object, then it calls toString with the (possibly zero length) char[] array that is the %z format qualifier. This call goes right to the overloaded version of this function in the class (remember, the compiler is smart enough to make all functions virtual). This class is then responsible for dealing with the qualifier. If your class doesn't deal with qualifiers, then you throw the exception if it is nonzero length. If you do, then you throw an exception if you don't recognize the format. Etc... Please clarify if I'm missing something, but this seems 100% typesafe to me - provided that the underlying printf varargs architecture is also typesafe.There a different representations, like hex, oct, dec, left, right, etc. but doesn't %h only work for type char because printf uses varargs converting chars into ints? I'm just used to the bare %magic being used to specify type. That notion should die and be replaced with type safety. Representation descriptors would still be valid, but in many cases a sane default should be acceptable. Make character type look like characters, make numbers look like numbers, etc.Ah, yes. I see what you're saying now. And I totally agree. One of my big gripes with %x/%X is that if the high bit is 1, then we always get a 8-character printf string: printf("%x",(signed char)-1) prints "FFFFFFFF" whereas I wish it would print "FF". The hack around that that I found was to convert my arg to an UNsigned char...so that when it's promoted to a long, it is filled with 0's. Then printf works as I would like. In D's printf, passing a char should make the format default to only printing 2 characters (or less).We could go with the Perl syntax here (shudder). Use the dot operator to concatenate (formatted) strings. Any time that the compiler sees something of the form: char[] . foo It converts it internally to char[] + format(foo) where format(...) is a series of library routines that convert various things into char[]. The format(object) just calls toString() to do it. But now we have the problem of how to do format Ofc, this all requires that Walter implement some special case code for char[]...but one of the stated objectives of D was "Languages should be good at handling strings." Another thought. Instead of only making this work for char[], you could make it work for all array types. Earlier, in a discussion about casts, somebody talked about actually passing a type (not a value) as a parameter into a cast function: int i = cast(int,foo); We could do a similar thing with the . operator on arrays. char[] str = "" . foo . bar . baz; Is expanded to: char[] str = "" + format(char[],foo) + format(char[],bar) + format(char[],baz); I thought about using the cast syntax, but that becomes cloudy when the argument you're trying to format is a pointer or another array.Well, I guess the very first thing we ought to decide what type of syntax we want. If we go all procedural, we are ok. You said you would need a format property in your idea. I think I like that, but I'm not sure how to best leverage it. In any case that is something we would have to be Walter for. Likewise, if we want more on an expression based syntax, we either have to kludge around with the built-in types in D or we have to beg Walter to add a couple more primitives, with operators. At that point I'd say we are work in the language itself though and not in the library.I looks to me like a hack to get around the lack of operator overloads.Very true. It is very ugly; it was just a brainstorm to get things started. :)I'm also having trouble being objective coming up with something looks like it fits D's ideology. I'm real partial to C++'s i/o and in D that's right out. I like the suggestion you had above for %magic on object types but I don't think it goes far enough.I Walter doesn't mind the overloaded . operator idea, you could use << and >> instead: char[] str = "" . foo; becomes char[] str = "" + format(char[],foo); and str >> foo; becomes foo = extract(typeof(foo),str); Or something like that. Still no (good) solution for format specifiers. -- 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))) ]
Oct 14 2001
Russ Lewis wrote:The key with strong typing is that you know what you know and you don't have to make wild guesses or assumptions. When the %z (or whatever) magic is passed, if the typesafe printf sees that the matching argument is anything but a pointer to an object, then it throws an exception. If it is an object, then it calls toString with the (possibly zero length) char[] array that is the %z format qualifier. This call goes right to the overloaded version of this function in the class (remember, the compiler is smart enough to make all functions virtual). This class is then responsible for dealing with the qualifier. If your class doesn't deal with qualifiers, then you throw the exception if it is nonzero length. If you do, then you throw an exception if you don't recognize the format. Etc... Please clarify if I'm missing something, but this seems 100% typesafe to me - provided that the underlying printf varargs architecture is also typesafe.Well are typesafe in that it will always be a descendant of Object. But you can't be more specific. (I don't mean just any Fruit. I want an Apple!) You will always get the streamify routine for the Object you pass, but I guess I would like to say what type of Object I expect and get en error otherwise, like you would with builtin types. Not a show stopper by any means.Well, I guess I would rather that D would always print a char as a char/glyph, unless I cast it to something else (like an unsigned) in which case I would like to to print way ever I passed it. I do agree that in some cases there is format information that is useful and not associated to the type (unless we attach a format property; probably overkill) like hex/oct/dec, left/right/center, and the like, but I don't think I like the use of the format character as an end run around a cast. I C you didn't have a choice. printf only saw ints.There a different representations, like hex, oct, dec, left, right, etc. but doesn't %h only work for type char because printf uses varargs converting chars into ints? I'm just used to the bare %magic being used to specify type. That notion should die and be replaced with type safety. Representation descriptors would still be valid, but in many cases a sane default should be acceptable. Make character type look like characters, make numbers look like numbers, etc.Ah, yes. I see what you're saying now. And I totally agree. One of my big gripes with %x/%X is that if the high bit is 1, then we always get a 8-character printf string: printf("%x",(signed char)-1) prints "FFFFFFFF" whereas I wish it would print "FF". The hack around that that I found was to convert my arg to an UNsigned char...so that when it's promoted to a long, it is filled with 0's. Then printf works as I would like. In D's printf, passing a char should make the format default to only printing 2 characters (or less).We could go with the Perl syntax here (shudder). Use the dot operator to concatenate (formatted) strings. Any time that the compiler sees something of the form: char[] . foo It converts it internally to char[] + format(foo) where format(...) is a series of library routines that convert various things into char[]. The format(object) just calls toString() to do it. But now we have the problem of how to do formatActually, this isn't how perl does formatting. Your choices in perl are (s)printf and format lines like: format FOO price: $<<<<< tax: $>>>> $thePrice, $theTax to say the first value will be left justified and the second will be right justified. (I have the syntax wrong, but it's the general idea. You then have to tell the interpreter which format you are using for a given filehandle and then you do a write like so: ($thePrice, $theTax) = ($something, $somethingelse); write myFileHandle;Ofc, this all requires that Walter implement some special case code for char[]...but one of the stated objectives of D was "Languages should be good at handling strings."Oh, for string handling. I was thinking of something comparable to C's strtok, sprintf, index, etc except (hopefully) better. If we can come up with an easy way to say "make this string 8 chars wide, center the characters in the string and uppercase the first letter" in a very concise way, then print formatting is easy. Kind of like reducing printf to {return puts(sprintf(ARGS))}; Now if it's not very abbreviated, it's going to suck. printf was very brief. C++ wasn't as brief, but with the exception that some modifiers were persistent and some were one shot, it conveyed the idea fairly elegantly. It needs some work though in terms of ease of use. I've found the single argument, overloaded write/writeln scheme to be a bit clumsy. With good string formating, the printing may be less of an issue sincec we can build the string and print it as a single argument, but I still believe there will be needless memory/cpu overhead with such a scheme. If you do a lot of i/o, you'll run the cpu ragged collecting the temporaries when you're not in i/o wait.Another thought. Instead of only making this work for char[], you could make it work for all array types. Earlier, in a discussion about casts, somebody talked about actually passing a type (not a value) as a parameter into a cast function: int i = cast(int,foo);I think that got shot down because the type could not be determined until the semantic pass.We could do a similar thing with the . operator on arrays. char[] str = "" . foo . bar . baz;Dot won't work. It could be a member dereference, or it could be a concatenation. Actually, perl 6 is switching . to _ so that they switch -> to . like all other OO languages. That's academic though. We can find another operator.Is expanded to: char[] str = "" + format(char[],foo) + format(char[],bar) + format(char[],baz); I thought about using the cast syntax, but that becomes cloudy when the argument you're trying to format is a pointer or another array.Actually, format is looking a lot like a synonym for cast. How would you use the scheme to justify, set field width, or print a number in hex?It's not that I'm fixated on the >>/<< operators. It's that I am fixated on expressions as opposed to calls. I don't see a clean way to do that in a library w/o overloading operators or variable arguments. I also like the fact that user defined type can be printed like any first class Object. Treating Objects like first class types has been met with near hostility here. I think the might be a good hint that D i/o probably should try to blur that line no matter how much I may want to. DanI'm also having trouble being objective coming up with something looks like it fits D's ideology. I'm real partial to C++'s i/o and in D that's right out. I like the suggestion you had above for %magic on object types but I don't think it goes far enough.I Walter doesn't mind the overloaded . operator idea, you could use << and >> instead: char[] str = "" . foo; becomes char[] str = "" + format(char[],foo); and str >> foo; becomes foo = extract(typeof(foo),str); Or something like that. Still no (good) solution for format specifiers.
Oct 19 2001
a wrote:Russ Lewis wrote:Remember that all member functions of classes are automatically virtual in D (when necessary). Thus, if you pass a Fruit* pointer (which is cast down to an Object*), then when you call toString(), you get Fruit::toString. You get complete control. And if the formatter arguments you pass with it don't make sense for Fruit::toString, then it throws an exception.The key with strong typing is that you know what you know and you don't have to make wild guesses or assumptions. When the %z (or whatever) magic is passed, if the typesafe printf sees that the matching argument is anything but a pointer to an object, then it throws an exception. If it is an object, then it calls toString with the (possibly zero length) char[] array that is the %z format qualifier. This call goes right to the overloaded version of this function in the class (remember, the compiler is smart enough to make all functions virtual). This class is then responsible for dealing with the qualifier. If your class doesn't deal with qualifiers, then you throw the exception if it is nonzero length. If you do, then you throw an exception if you don't recognize the format. Etc... Please clarify if I'm missing something, but this seems 100% typesafe to me - provided that the underlying printf varargs architecture is also typesafe.Well are typesafe in that it will always be a descendant of Object. But you can't be more specific. (I don't mean just any Fruit. I want an Apple!) You will always get the streamify routine for the Object you pass, but I guess I would like to say what type of Object I expect and get en error otherwise, like you would with builtin types. Not a show stopper by any means.Well, I guess I would rather that D would always print a char as a char/glyph, unless I cast it to something else (like an unsigned) in which case I would like to to print way ever I passed it. I do agree that in some cases there is format information that is useful and not associated to the type (unless we attach a format property; probably overkill) like hex/oct/dec, left/right/center, and the like, but I don't think I like the use of the format character as an end run around a cast. I C you didn't have a choice. printf only saw ints.Makes sense. We just have to implement the printf() routine...but I agree that this is a good default.I meant it not as a formatting routine, but as an easy concatenation routine. If you used char[] . foo , it would call format to convert foo to a char[], then concatenate the arrays. If you wanted explicit formating strings, you would call char[] . format(foo, options)We could go with the Perl syntax here (shudder). Use the dot operator to concatenate (formatted) strings. Any time that the compiler sees something of the form: char[] . foo It converts it internally to char[] + format(foo) where format(...) is a series of library routines that convert various things into char[]. The format(object) just calls toString() to do it. But now we have the problem of how to do formatActually, this isn't how perl does formatting. Your choices in perl are (s)printf and format lines like:Unfortunately, we can't really describe it easily even in English...not terribly likely we're going to be able to better in a programming language without creating some weird new language (like printf did). :(Ofc, this all requires that Walter implement some special case code for char[]...but one of the stated objectives of D was "Languages should be good at handling strings."Oh, for string handling. I was thinking of something comparable to C's strtok, sprintf, index, etc except (hopefully) better. If we can come up with an easy way to say "make this string 8 chars wide, center the characters in the string and uppercase the first letter" in a very concise way, then print formatting is easy.Kind of like reducing printf to {return puts(sprintf(ARGS))};BTW, as you imply here, I very much think that sprintf should NOT take the buffer as an argument, but instead should return the string it creates. Either that or require arrays (no pointers). I don't want to mess with buffer overflows anymore. Or with having to calculate ahead of time how much buffer space I'll need.By adding an extra argument that allows the user to pass format specifiers. The problem with unifying format and cast is: int i = ...; char *ptr = format(char*,i); char[] str = format(char[],i); The first should cast the value i into a ptr whose address is i. The latter should create a char[] which contains a string which is the decimal representation of i. We need to keep these totally distinct. -- 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))) ]Is expanded to: char[] str = "" + format(char[],foo) + format(char[],bar) + format(char[],baz); I thought about using the cast syntax, but that becomes cloudy when the argument you're trying to format is a pointer or another array.Actually, format is looking a lot like a synonym for cast. How would you use the scheme to justify, set field width, or print a number in hex?
Oct 19 2001
that canWell, at the very least, I'd like to have a toStream methodI hope the hell somebody goes through D and standardizes capitalization before it goes public, or better yet get rid of case sensitivity. That was one of the few things I really liked about Pascal and that I now miss.default to toString. The human readable format is not always the best/most complete way to store to a file.I'm not sure really. I guess I was thinking: form F = <manipulator(s)>; // custom stdio.print(v1, hex(v2), F(v3)); // default form, hex form, my custom form But think makes it difficult or applets nasty looking to apply multiple format manipulator to a single variable in the print statement. stdio.print(hex(width(3, right(v1)))); // lisp anyone I don't think I would want to have to declare a format type for every custom manipulation. It would give us one of the worst drawbacks of COBOL's and perl's record based output without the benefits. I'm also having trouble being objective coming up with something looks like it fits D's ideology. I'm real partial to C++'s i/o and in D that's right out. I like the suggestion you had above for %magic on object types but I don't think it goes far enough. Would help to work out a formalized set of string ops to build upon? Most I/O will either be binary records or text strings I would assume. The binary output wouldn't need much in the way of formatting. fixed record sizes, byte and bit ordering and that sort of thing should do. It's with the human readable that we worry and justification, representation, padding, text formation of complex types. Maybe we would have a better feel for what feels right for printing strings in D once we get a feel for what it would be like to just muck around with strings in D.Binary files could be built on strings (since strings don't rely on that nasty trailing NULL character to determine their length, as in C/C++). Strings in general should be easy to manipulate. There's only a few things you'd want to do to any string: field width, justification, alignment, and padding (all can be implemented once as a function and will otherwise work for all types) and for any printable item to change type of conversion applied (These can be simple function calls probably with overloading, such as hex(int) and hex(char). I don't know about anyone else here, but I'm all for building my strings in memory and then dumping them off in a block to the file or stdout or whatever at reasonable intervals (such as each line). Especially if you can somehow cause the string to reserve enough memory to hold the biggest batch before you start. The big advantage is you should be able to use these methods on all your strings, not just strings going to stdout/cout/whatever. That one separation enables every kind of stream to have formatting, without having any stream have to implement or even wrap printf. All you'd need is an equivalent to puts(). Sean
Nov 04 2001
"Sean L. Palmer" wrote:The only problem is you have to make sure no character conversion silliness is going on. You also have to know what sizeof(char). You have to know that some deranged systems aren't converting '\n' into two characters. It's better to have a way to tell the code not to do any of that.that canWell, at the very least, I'd like to have a toStream methodI hope the hell somebody goes through D and standardizes capitalization before it goes public, or better yet get rid of case sensitivity. That was one of the few things I really liked about Pascal and that I now miss.default to toString. The human readable format is not always the best/most complete way to store to a file.I'm not sure really. I guess I was thinking: form F = <manipulator(s)>; // custom stdio.print(v1, hex(v2), F(v3)); // default form, hex form, my custom form But think makes it difficult or applets nasty looking to apply multiple format manipulator to a single variable in the print statement. stdio.print(hex(width(3, right(v1)))); // lisp anyone I don't think I would want to have to declare a format type for every custom manipulation. It would give us one of the worst drawbacks of COBOL's and perl's record based output without the benefits. I'm also having trouble being objective coming up with something looks like it fits D's ideology. I'm real partial to C++'s i/o and in D that's right out. I like the suggestion you had above for %magic on object types but I don't think it goes far enough. Would help to work out a formalized set of string ops to build upon? Most I/O will either be binary records or text strings I would assume. The binary output wouldn't need much in the way of formatting. fixed record sizes, byte and bit ordering and that sort of thing should do. It's with the human readable that we worry and justification, representation, padding, text formation of complex types. Maybe we would have a better feel for what feels right for printing strings in D once we get a feel for what it would be like to just muck around with strings in D.Binary files could be built on strings (since strings don't rely on that nasty trailing NULL character to determine their length, as in C/C++).Strings in general should be easy to manipulate. There's only a few things you'd want to do to any string: field width, justification, alignment, and padding (all can be implemented once as a function and will otherwise work for all types) and for any printable item to change type of conversion applied (These can be simple function calls probably with overloading, such as hex(int) and hex(char).This could be ok if the syntax doesn't get so complex as to take a way from what you are trying to format. printf fans/fiends often like how you get a feel for how the output will like by looking at the format string. I am also a little concerned about how to do alignment though before you send to the stream since that usual depends on stream state.I don't know about anyone else here, but I'm all for building my strings in memory and then dumping them off in a block to the file or stdout or whatever at reasonable intervals (such as each line). Especially if you can somehow cause the string to reserve enough memory to hold the biggest batch before you start. The big advantage is you should be able to use these methods on all your strings, not just strings going to stdout/cout/whatever. That one separation enables every kind of stream to have formatting, without having any stream have to implement or even wrap printf. All you'd need is an equivalent to puts().I've mentioned this before myself. The problem is that you have to know ahead of time what the largest batch is going to be. Some (many, I) would consider that an unnecessary pain. It also adds yet another buffer layer between the print and the final destination. This uses more clock cycles to build a temp string and it and a requires more memory to store our extra buffer. It will also require the the user the maintain the string to make sure it gets reused, or you have to count on GC to not go nuts when the program does a lot of io. printf didn't need to build such a buffer. It analyzed the arguments to be printed one at a time. What ever D has will be compared to printf, unless it is printf. If we replace printf, it better be good so we don't get as many people complaining about it as C++ iostreams has. Dan
Nov 04 2001
Are you implying that .toString() is a "magic method" that will be invoked automatically by printf? That's a plausible approach. It makes it more important that it be easy to concatenate strings. Do remember to allow for usages such as: printf (x.asHead(1, 10) + " " + y.asHead(1, 13) + ...); or some suitable substitute. N.B.: here I was assuming that the asHead methods took the self layout formatting. E.g., if one wanted to produce: This is And This is x y ======= =========== one could do: printf (x.asHead(1, 10) + " " + y.asHead(1, 13) + "\n"); printf (x.asHead(2, 10) + " " + y.asHead(2, 13) + "\n"); printf (x.asHead(3, 10) + " " + y.asHead(3, 13) + "\n"); persuming that the objects could determine their names.
Oct 17 2001
Charles Hixson wrote:Are you implying that .toString() is a "magic method" that will be invoked automatically by printf?We have been using the term "magic" to refer to the printf format specifiers. We were thinking that we could add a new specifier to format objects. The idea is that when printf sees that specifier, it thinks the argument is a pointer to an object, and so calls the toString() method on it. It won't work - not safely, anyhow - unless we can get some sort of typesafe printing routine, so we don't mistakenly think that an int is a pointer or vice-versa. -- 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))) ]
Oct 17 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 theformatting capabilities of printf. Iwould also challenge anybody to write cout code that expresses, as clearlyas the printf format string, howthe stuff will actually look on the screen. IMHO, printf shines where you need complex formatting and/or the argumentsare 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.
Oct 11 2001