@Lee's answer is correct as per a possible workaround, but it does not describe what happens with your code.
In an expression printf "foo"
, the "foo"
is not a string to be formatted. Instead, it is input formatter by itself. More specifically, it is a string literal used to infer the actual type of the TextWriterFormat<'T>
.
The signature of printf
is:
printf : TextWriterFormat<'T> -> 'T
Since printfn ("DANNY")
does not contain any format specifiers, the F# compiler infers a TextWriterFormat<unit>
, and the entire expression becomes printfn ("DANNY") ()
.
With a variable, it's impossible to statically predict what format specifiers will be there. Consider if ToLongTimeString()
method was able to return strings of "%s"
or "%d %d %d"
, what would be the prototype of the returned function?
When inferring the correct type, a string literal works fine, but the variable or let
-binding does not work:
let foo1 = "foo"
let bar = printf foo // does not compile
[<Literal>] let foo2 = "foo";; // see update below
let bar = printf foo2 // compiles fine
In any case, it looks much safer to always use format specifiers:
printf "%s" "DANNY"
printf "%s" (DateTime.Now.ToLongTimeString())
Update: don't forget to type double colon ;;
after [<Literal>]
value to avoid warning FS0058 in VS2013.
printf
toprint format
, why not aprint
that just prints without formatting? It's easy enough to define aslet print (x : string) = printf "%s" x
but that seems really silly and possibly inefficient. – Dustclothprint
as an alias of Console.WriteLine. github.com/fsharp/fslang-suggestions/issues/1092 – Colloquium