From mboxrd@z Thu Jan 1 00:00:00 1970 Received: (from weis@localhost) by pauillac.inria.fr (8.7.6/8.7.3) id SAA29968 for caml-redistribution; Tue, 18 Feb 1997 18:39:46 +0100 (MET) Received: (from xleroy@localhost) by pauillac.inria.fr (8.7.6/8.7.3) id RAA28850; Tue, 18 Feb 1997 17:39:40 +0100 (MET) From: Xavier Leroy Message-Id: <199702181639.RAA28850@pauillac.inria.fr> Subject: Re: string variables in Printf.* calls: Bug, or lack of understanding? In-Reply-To: <199702131831.NAA22295@abetti> from "T. Kurt Bond" at "Feb 13, 97 01:31:02 pm" To: thomas.k.bond@cpmx.saic.com (T. Kurt Bond) Date: Tue, 18 Feb 1997 17:39:40 +0100 (MET) Cc: caml-list@pauillac.inria.fr, tkb@wvlink.mpl.com MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Sender: weis > Objective Caml version 1.03 > > [1] # let s = "%f" in Printf.printf s 10.5;; > Characters 30-31: > This expression has type string but is here used with type > ('a, out_channel, unit) format > > [2] # Printf.printf "%f" 10.5;; > 10.500000- : unit = () > > I don't understand why the variable s, which is bound to a string value, > causes the error in statement 1, while using a literal string in > statement 2 works as expected. Can anyone explain? Or is this a bug? It's a feature: format strings are typed specially in order to make printf type-safe. Look at the type for Printf.printf: it's ('a, out_channel, unit) format -> ... and not string -> ... A format string is typed specially and receives a type of the form (t1, t2, t3) format, for suitable types t1, t2, t3. For instance, the format string ``%f %d'' has type (float -> int -> 'b, 'c, 'b) format which, when passed as first argument to Printf.printf, gives the return type float -> int -> unit which ensures that the next two arguments are a float and an integer, as expected. Now comes the dirty hack. In an ideal world, there would be a different syntax for string literals and for format literals, so that the type-checker would always know whether to type the literal as a string or as a format. For backward compatibility, and because we are somehow running out of quote characters, format literals have actually the same syntax as strings, and it's the type expected by the context of the literal that says whether to type it as a string or as a format. In some sense, the syntax for string literals is overloaded for format literals as well. In particular, when a string literal occur as first argument to Printf.printf (your example [2]), its expected type is ('a, out_channel, unit) format and thus the type-checker types it as a format literal. In other contexts, such as your example [1] above, there is no expected type and the literal is therefore typed as a string. However, you can force the correct behavior with a type constraint: let s = ("%f" : ('a, 'b, 'c) format) in Printf.printf s 10.5;; You can actually go quite far this way, and use formats as first-class values (pass them as arguments to functions, etc) -- all in a type-safe way. Just remember to put a type constraint around format literals if the context does not already expect a format type. - Xavier Leroy