OMGtechy
OMGtechy

Reputation: 8220

System.Console.WriteLine() vs printfn in F#

What is the difference between the following two statements in F#? Are they any advantages or disadvantages compared to each other (excluding the obvious syntax differences)?

I understand that WriteLine() is part of .NET, but do not understand what implications this might have.

The Sample Code:

printfn "This is an integer: %d" 5
System.Console.WriteLine("This is an integer: {0}" , 5)

Upvotes: 26

Views: 20054

Answers (4)

Eamon Nerbonne
Eamon Nerbonne

Reputation: 48066

printfn and its various cousins have several advantages:

  • They're shorter.
  • They can do some static type checking; i.e. printfn "%d" "bad type" will not compile.
  • ...but you don't have to do static type checking; %O prints any object
  • They can print "smart" representations for things like arrays, tuples, and discriminated unions with %A
  • They can be partially applied; i.e. printfn "%d, %d" 3 is a valid expression. This is particularly nifty since the compiler can check that you actually apply the right number of arguments when you later use this subexpression - unlike Console.WriteLine which will happily accept too many or too few parameters.

In practice, the most common partial application is likely to include just the format string; e.g.

let printParticle = printfn "Particle at (%d, %d), state %A, p = %f"

printParticle 2 3 //compile time warning about ignored value
printParticle 3 4 someState 0.4 //fine
printParticle 5 6 someState 0.4 0.7 //compile-time error

However, prior to F# 3.1, it's also slow. It's plenty fast enough to keep up with you the coder, but if you're using it in some form of serialization, it could turn into a bottleneck. The F# 3.1 release announcement (which is distributed as part of Visual Studio 2013) claims to improve the performance dramatically, though I have not verified this.

Personally, I usually use printfn for exploratory coding, and then I largely stick to %A with the occasional other specifier thrown in. However, the .NET native string formatting is still useful in some cases for its detailed culture and formatting-related options. If you want maximum speed direct concatenation (or a StringBuilder) will easily outperform both as this avoids interpreting the format string.

Upvotes: 42

N_A
N_A

Reputation: 19897

Aside from style, System.Console.WriteLine has the advantage of being able to reuse parameters, i.e. System.Console.WriteLine("This is a integer twice: {0} {0}", 5)

Also, as noted here, you can do pretty printing of F# object using printfn which you can't do with System.Console.WriteLine and since it doesn't take a tuple, you can do partial application with it.

As noted by others, printfn uses reflection and thus is significantly slower than PrintLine, but also is typesafe.

Upvotes: 4

pad
pad

Reputation: 41290

Here are some pros and cons of printf-like functions compared to Console.WriteLine.

Pros:

  • printfn functions are type-safe:

    printfn "This is an integer: %i" 5 // works
    printfn "This is an integer: %i" "5" // doesn't compile
    
  • It's easy to do partial application with printfn, which is not the case with Console.WriteLine due to excessive number of overloads:

    [1; 2; 3] |> List.iter (printfn "%i; ")
    
  • printfn support F# types better via %A specifier.

Cons:

Aside from not being able to reuse parameters as @mydogisbox mentioned, printfn-like functions are much slower than Console.WriteLine (due to using reflection); you shouldn't use the former for logging purpose.

Upvotes: 8

Malvin Butterfinger
Malvin Butterfinger

Reputation: 546

The printfn function can be partially applicated.

let printDouble = printfn "%f"
printDouble 2.0

As the standard .NET functions take tuples as parameters in F#, you can't use partial application there.

A second advantage of printfn is, that the arguments are typed. So this won't compile:

let printDouble = printfn "%d"
printDouble 2.0

Upvotes: 4

Related Questions