Jump to page: 1 2
Thread overview
typesafe printf
Aug 24, 2001
Russ Lewis
Aug 24, 2001
Charles Hixson
Aug 24, 2001
Russ Lewis
Aug 27, 2001
Charles Hixson
Aug 27, 2001
Russ Lewis
Aug 28, 2001
John Carney
Aug 28, 2001
Russ Lewis
Aug 29, 2001
John Carney
Aug 29, 2001
Russ Lewis
Aug 30, 2001
John Carney
Aug 29, 2001
Chris Friesen
August 24, 2001
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"

August 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.


August 24, 2001
Charles Hixson wrote:

> 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.

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?

August 27, 2001
Russ Lewis wrote:
> Charles Hixson wrote:
> 
> 
>>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.
>>
> 
> 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?
> 
> 

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.

August 27, 2001
Charles Hixson wrote:

> Russ Lewis wrote:
> > Charles Hixson wrote:
> >
> >
> >>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.
> >>
> >
> > 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?
> >
> >
>
> 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.

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.

August 28, 2001
"Russ Lewis" <russ@deming-os.org> wrote in message news:3B8A963E.52BCC7C2@deming-os.org...
> Charles Hixson wrote:
>
> > Russ Lewis wrote:
> > > Charles Hixson wrote:
> > >
> > >
> > >>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.
> > >>
> > >
> > > 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?
> > >
> > >
> >
> > 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.
>
> 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.

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.


August 28, 2001
John Carney wrote:

> > 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.
>
> 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.

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.

August 29, 2001
"Russ Lewis" <russ@deming-os.org> wrote in message news:3B8BB246.735ECA86@deming-os.org...
> John Carney wrote:
>
> > 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.
>
> 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.

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 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.

printf ("And we're %d%% with you on that one\n", 10 * 10)


August 29, 2001
John Carney wrote:

> "Russ Lewis" <russ@deming-os.org> wrote in message news:3B8BB246.735ECA86@deming-os.org...
> > 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.
>
> 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?

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.

> printf ("And we're %d%% with you on that one\n", 10 * 10)

LOL!

August 29, 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
« First   ‹ Prev
1 2