D - typesafe printf
- Russ Lewis (31/31) Aug 24 2001 I was thinking about printf, and was looking for some way to implement
- Charles Hixson (7/11) Aug 24 2001 How about a toPrint(char[] fmt = "7.0") method in Object. Then any
- Russ Lewis (4/15) Aug 24 2001 I'm sorry but I'm not sure how this solves the problem of making printf(...
- Charles Hixson (9/33) Aug 27 2001 printf just calls the toPrint method of each class in turn. It's the
- Russ Lewis (7/40) Aug 27 2001 Ok, I see. You're talking, like me, about compiler expansion of the pri...
- John Carney (17/61) Aug 28 2001 implement
- Russ Lewis (10/20) Aug 28 2001 What I was getting at was that with your solution (where the complier pi...
- John Carney (15/28) Aug 29 2001 the
- Russ Lewis (17/29) Aug 29 2001 I get the feeling that one of us is missing something. Hope it isn't me...
-
John Carney
(4/13)
Aug 30 2001
- Chris Friesen (7/30) Aug 29 2001 This sounds like an interesting idea. I think it could work out quite n...
I was thinking about printf, and was looking for some way to implement it in D that would be typesafe. I've played around with suggesting that we add a .typeid to variables, and putting typeid information into the varargs[] array, but I think I stumbled on something better: Expand variable-argument list functions into recursive calls. Thus, the compiler would expand printf("a = %d, b = %d, ans = %s", a,b,ans); into printf(printf(printf("a = %d, b = %d, ans = %s",a),b),ans); The innermost printf would return the string ", b = %d, ans = %s", the next would return ", ans = %s", and the last would return an empty string. Then you might implement printf this way: char[] printf(char [],...) out(result) { assert(result == ""); }; char[] printf(char[], int) {....}; char[] printf(char[], float) {....}; char[] printf(char[], char[]) {....}; char[] printf(char[], double) {....}; char[] printf(char[], void*) {....}; char[] printf(char[], Object) {....}; // calls Object.toString() Any time that you pass an invalid argument type to the printf statement, it will throw an InvalidPrintfArgumentException or some such. I think that eventually, with optimizing compilers, the compiler might unwrap this entire mess into an inline expression of some sort. It would be cool to compile something, have the compiler do some analysis, and have it give a compile error: foo.d line 947: printf() will throw InvalidPrintfArgumentException() = "%d print format specifier used with pointer argument"
Aug 24 2001
Russ Lewis wrote:I was thinking about printf, and was looking for some way to implement it in D that would be typesafe. I've played around with suggesting ... "%d print format specifier used with pointer argument"How about a toPrint(char[] fmt = "7.0") method in Object. Then any class that wanted to could implement it as it choose. And the default implementation could just call toString. Then when printf interpreted the format string, it could call to toPrint method of the class. You could even have a default action of "append to the end of the composed string" to handle the case where not enough formats were provided.
Aug 24 2001
Charles Hixson wrote:Russ Lewis wrote:I'm sorry but I'm not sure how this solves the problem of making printf() typesafe. How does printf know the type of the argument so that it knows which toPrint() to call?I was thinking about printf, and was looking for some way to implement it in D that would be typesafe. I've played around with suggesting ... "%d print format specifier used with pointer argument"How about a toPrint(char[] fmt = "7.0") method in Object. Then any class that wanted to could implement it as it choose. And the default implementation could just call toString. Then when printf interpreted the format string, it could call to toPrint method of the class. You could even have a default action of "append to the end of the composed string" to handle the case where not enough formats were provided.
Aug 24 2001
Russ Lewis wrote:Charles Hixson wrote:printf just calls the toPrint method of each class in turn. It's the job of the class to figure out how to print itself. So if you say: printf ("13%5% rummaging around %3.1% picnic tables", "bears", 23); this would be parsed into: puts("13" + "bears".toPrint("5") + " rummaging around " + 23.toPrint("3.1") + " picnic tables"); Which looks typesafe to me. Of course, Integer would need to decide what to do with a format item of "3.1", but that's Integer's problem.Russ Lewis wrote:I'm sorry but I'm not sure how this solves the problem of making printf() typesafe. How does printf know the type of the argument so that it knows which toPrint() to call?I was thinking about printf, and was looking for some way to implement it in D that would be typesafe. I've played around with suggesting ... "%d print format specifier used with pointer argument"How about a toPrint(char[] fmt = "7.0") method in Object. Then any class that wanted to could implement it as it choose. And the default implementation could just call toString. Then when printf interpreted the format string, it could call to toPrint method of the class. You could even have a default action of "append to the end of the composed string" to handle the case where not enough formats were provided.
Aug 27 2001
Charles Hixson wrote:Russ Lewis wrote:Ok, I see. You're talking, like me, about compiler expansion of the printf into another expression that does NOT use variable numbers of arguments and is typesafe. Functionally, I think yours would work (you expand printf into the Java style of printing), but it requires (I would guess) a lot more smarts in the compiler. With a recursive call, (nearly) all of the smarts are in the library rather than the compiler.Charles Hixson wrote:printf just calls the toPrint method of each class in turn. It's the job of the class to figure out how to print itself. So if you say: printf ("13%5% rummaging around %3.1% picnic tables", "bears", 23); this would be parsed into: puts("13" + "bears".toPrint("5") + " rummaging around " + 23.toPrint("3.1") + " picnic tables"); Which looks typesafe to me. Of course, Integer would need to decide what to do with a format item of "3.1", but that's Integer's problem.Russ Lewis wrote:I'm sorry but I'm not sure how this solves the problem of making printf() typesafe. How does printf know the type of the argument so that it knows which toPrint() to call?I was thinking about printf, and was looking for some way to implement it in D that would be typesafe. I've played around with suggesting ... "%d print format specifier used with pointer argument"How about a toPrint(char[] fmt = "7.0") method in Object. Then any class that wanted to could implement it as it choose. And the default implementation could just call toString. Then when printf interpreted the format string, it could call to toPrint method of the class. You could even have a default action of "append to the end of the composed string" to handle the case where not enough formats were provided.
Aug 27 2001
"Russ Lewis" <russ deming-os.org> wrote in message news:3B8A963E.52BCC7C2 deming-os.org...Charles Hixson wrote:implementRuss Lewis wrote:Charles Hixson wrote:Russ Lewis wrote:I was thinking about printf, and was looking for some way to...it in D that would be typesafe. I've played around with suggestingprovided."%d print format specifier used with pointer argument"How about a toPrint(char[] fmt = "7.0") method in Object. Then any class that wanted to could implement it as it choose. And the default implementation could just call toString. Then when printf interpreted the format string, it could call to toPrint method of the class. You could even have a default action of "append to the end of the composed string" to handle the case where not enough formats wereprintf()I'm sorry but I'm not sure how this solves the problem of makingknows whichtypesafe. How does printf know the type of the argument so that itprintf intoOk, I see. You're talking, like me, about compiler expansion of thetoPrint() to call?printf just calls the toPrint method of each class in turn. It's the job of the class to figure out how to print itself. So if you say: printf ("13%5% rummaging around %3.1% picnic tables", "bears", 23); this would be parsed into: puts("13" + "bears".toPrint("5") + " rummaging around " + 23.toPrint("3.1") + " picnic tables"); Which looks typesafe to me. Of course, Integer would need to decide what to do with a format item of "3.1", but that's Integer's problem.another expression that does NOT use variable numbers of arguments and istypesafe.Functionally, I think yours would work (you expand printf into the Javastyle ofprinting), but it requires (I would guess) a lot more smarts in thecompiler. With arecursive call, (nearly) all of the smarts are in the library rather thanthecompiler.Huh? I'd say just the opposite. It's the library that's picking apart the string, not the compiler. I must say I like the toPrint() solution much better because it doesn't involve any implicit recursion. Regards, John Carney.
Aug 28 2001
John Carney wrote:What I was getting at was that with your solution (where the complier picks apart the string and recreates it) the compiler must know a lot about printf and its format specifiers. At least, it knows a lot about the % character. I'm thinking that it would be better to have a design where the compiler knew nothing about what the function was for or how it works. This allows the compiler to define a single syntax for variable-argument lists and have it work for any range of functions people might implement. This also simplifies compiler implementation by allowing it less knowledge of the library. A simple compiler is nearly always a more correct compiler.Functionally, I think yours would work (you expand printf into the Javastyle ofprinting), but it requires (I would guess) a lot more smarts in thecompiler. With arecursive call, (nearly) all of the smarts are in the library rather thanthecompiler.Huh? I'd say just the opposite. It's the library that's picking apart the string, not the compiler. I must say I like the toPrint() solution much better because it doesn't involve any implicit recursion.
Aug 28 2001
"Russ Lewis" <russ deming-os.org> wrote in message news:3B8BB246.735ECA86 deming-os.org...John Carney wrote:theHuh? I'd say just the opposite. It's the library that's picking apartpicksstring, not the compiler. I must say I like the toPrint() solution much better because it doesn't involve any implicit recursion.What I was getting at was that with your solution (where the complierapart the string and recreates it) the compiler must know a lot aboutprintf andits format specifiers. At least, it knows a lot about the % character.Bzzzt! Who said anything about the compiler picking apart the string? Look up there where it says "It's the library that's picking apart the string, not the compiler." Why does the compiler need to know anything about how printf works for the "toPrint()" solution to work? Besides, it's not *my* solution - though I do wish it was :) Mind you, I would prefer "format()" to "toPrint()".I'm thinking that it would be better to have a design where the compilerknewnothing about what the function was for or how it works. This allows the compiler to define a single syntax for variable-argument lists and have itworkfor any range of functions people might implement. This also simplifies compiler implementation by allowing it less knowledgeofthe library. A simple compiler is nearly always a more correct compiler.printf ("And we're %d%% with you on that one\n", 10 * 10)
Aug 29 2001
John Carney wrote:"Russ Lewis" <russ deming-os.org> wrote in message news:3B8BB246.735ECA86 deming-os.org...I get the feeling that one of us is missing something. Hope it isn't me :) If you have the library pick apart the string, the it's doing it at runtime, right? That means that it will need type information at runtime. That's the problem with printf and the variable argument list it uses. If it sees a variable on the stack of size 4 and the data is 0x30310A00, it can't tell if is unsigned long l = 0x30310A00 char buf[] = "01\n" or Foo *myPtr = new Foo; It's just binary data. To do library parsing of the string, we have to include runtime type identification, which is UGLY. To really make it typesafe, you need to use the compiler to resolve a variable-argument call down to a series of known-argument calls with good typechecking. Then the library will know what you passed it, because the compiler calls the right function.What I was getting at was that with your solution (where the complierpicksapart the string and recreates it) the compiler must know a lot aboutprintf andits format specifiers. At least, it knows a lot about the % character.Bzzzt! Who said anything about the compiler picking apart the string? Look up there where it says "It's the library that's picking apart the string, not the compiler." Why does the compiler need to know anything about how printf works for the "toPrint()" solution to work?printf ("And we're %d%% with you on that one\n", 10 * 10)LOL!
Aug 29 2001
"Russ Lewis" <russ deming-os.org> wrote in message news:3B8D3EBD.F54188D2 deming-os.org...John Carney wrote:<snip>"Russ Lewis" <russ deming-os.org> wrote in message news:3B8BB246.735ECA86 deming-os.org...To really make it typesafe, you need to use the compiler to resolve a variable-argument call down to a series of known-argument calls with good typechecking. Then the library will know what you passed it, because the compiler calls the right function.I see your point. I still don't like it.printf ("And we're %d%% with you on that one\n", 10 * 10)LOL!
Aug 30 2001
Russ Lewis wrote:Expand variable-argument list functions into recursive calls. Thus, the compiler would expand printf("a = %d, b = %d, ans = %s", a,b,ans); into printf(printf(printf("a = %d, b = %d, ans = %s",a),b),ans); The innermost printf would return the string ", b = %d, ans = %s", the next would return ", ans = %s", and the last would return an empty string. Then you might implement printf this way: char[] printf(char [],...) out(result) { assert(result == ""); }; char[] printf(char[], int) {....}; char[] printf(char[], float) {....}; char[] printf(char[], char[]) {....}; char[] printf(char[], double) {....}; char[] printf(char[], void*) {....}; char[] printf(char[], Object) {....}; // calls Object.toString()This sounds like an interesting idea. I think it could work out quite nicely. -- Chris Friesen | MailStop: 043/33/F10 Nortel Networks | work: (613) 765-0557 3500 Carling Avenue | fax: (613) 765-2986 Nepean, ON K2H 8E9 Canada | email: cfriesen nortelnetworks.com
Aug 29 2001