Version française
Home     About     Download     Resources     Contact us    
Browse thread
ocaml 2.02 bug: curried printf
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Xavier Leroy <Xavier.Leroy@i...>
Subject: Re: ocaml 2.02 bug: curried printf
> This used to work in 2.01, but 2.02 outputs the wrong thing:

You're right that sprintf in 2.02 is broken w.r.t. partial application.
However, even after fixing the obvious bug, it might not do what you want.

The behavior of the *printf functions when partially applied
has always been a bit strange even before 2.02: sprintf did "the right
thing", but printf prints as much as it can without needing the
omitted arguments, then resumes printing when more arguments are
provided.  In your examples:

> 	let udt = [1; 2; 3] ;;
> 	iter (printf "foo%d") udt; print_newline () ;;

This prints "foo123" because the printing of "foo" was ``factored out''.

> 	iter (fun s -> printf "foo%d" s) udt; print_newline ()

This prints "foo1foo2foo3" because printf is no longer partially applied.

For sprintf, the old implementation was purely functional (a list of
string fragments is built, then concatenated), hence partial
application made no difference:

> 	map (sprintf "foo%d") udt
>       map (fun s -> sprintf "foo%d" s) udt

both return ["foo1"; "foo2"; "foo3"].

The new implementation of sprintf is based on an internal extensible
buffer, hence works by side-effects (just like printf, actually).
Hence, after fixing the obvious bug, we'd get the same "print as much
as possible" behavior that printf displays, thus

        let f = sprintf "foo%d" in
        let r1 = f 1 in
        let r2 = f 2 in
        (r1, r2)

would return ("foo1", "2"), while

        (sprintf "foo%d" 1, sprint "foo%d" 2)

still returns ("foo1", "foo2").

We can go back to the 2.01 implementation of sprintf, of course, but
it's less efficient than the one based on extensible buffers, and also
prevents interesting code sharing between sprintf and bprintf.

The alternative is to keep a buffer-based sprintf that is efficient
and consistent with printf ("consistent" in the sense of "as weird as"),
but is not really usable in partial application contexts.

Any opinions?

- Xavier Leroy