8

The following code does not compile:

let x = "hello" in
Printf.printf x

The error is:

Error: This expression has type string but an expression was expected of type
     ('a, out_channel, unit) format =
       ('a, out_channel, unit, unit, unit, unit) format6

1) Can someone give an explanation of the error message?

2) And why would a string cannot be passed to printf ?

Thomas
  • 5,047
  • 19
  • 30
Nicolas Viennot
  • 3,921
  • 1
  • 21
  • 22
  • even in C, it's bad practice to pass some variable string as the format to printf – newacct May 05 '12 at 09:12
  • @newacct: that's not so true, think of a dbg(const char *fmt, ...) function that you would declare yourself. – Nicolas Viennot May 05 '12 at 12:25
  • @NicolasViennot That would work fine in OCaml though: `let dbg fmt = Printf.printf fmt in dbg "%d %d" 1 2`. The only thing you can't do is to use a format string that you read from a file or as user input. – sepp2k May 05 '12 at 15:39
  • see also this question: http://stackoverflow.com/questions/10406493/ocaml-printf-sprintf – winitzki May 08 '12 at 11:27

2 Answers2

9

The first argument to printf must be of type ('a, out_channel, unit) format not string. String literals can be automatically converted to an appropriate format type, but strings in general can't.

The reason for that is that the exact type of a format string depends on the contents of the string. For example the type of the expression printf "%d-%d" should be int -> int -> () while the type of printf "%s" should be string -> (). Clearly such type checking is impossible when the format string is not known at compile time.

In your case you can just do printf "%s" x.

sepp2k
  • 363,768
  • 54
  • 674
  • 675
8

As sepp2k points out, in OCaml printf formats have a distinct type, and are not simply strings. String literals are converted automatically to printf formats, but x is not a string literal. If you want to give a name to a format, you can convert it explicitly yourself:

> let x = format_of_string "hello" in Printf.printf x
hello- : unit = ()

You can also cause the implicit conversion by specifying a type for x, but the types of formats are so complicated this is quite painful:

# let (x: ('a,'b,'c,'d,'d,'a) format6) = "hello" in Printf.printf x;;
hello- : unit = ()

(I personally don't understand the format6 type.)

Jeffrey Scofield
  • 65,646
  • 2
  • 72
  • 108
  • 1
    Note that like `printf` `format_of_string` can only be used with string literals, not arbitrary strings. So if you need `x` to be a string, you can't use it to turn `x` into a format just before printing it. – sepp2k May 05 '12 at 04:03
  • Absolutely. As you point out, the string needs to be known at compile time to get type safety. – Jeffrey Scofield May 05 '12 at 04:06
  • I guess that's the double edge sword of a strongly statically typed language :) – Nicolas Viennot May 05 '12 at 12:31