How "Functional" F# Really Is?

Is F# a functional language? Well, it definitely has functions and lambdas, but so does C#. One of the main selling points of F# is immutability of data. It seems to be a popular belief that in F# most data is immutable. I am not an F# guru, but after some practical F# programming, I have strong doubts about that.

Axiom: Immutable Data Is Good For Concurrency

There is no much doubt about it. If the data is immutable, you don't need to worry about it being corrupted by mutliple threads. The trouble is, having your data immutable shifts your paradigm and sometimes has performance implications.

Alleged Corollary: F# Is Good For Concurrency

In an MSDN magazine article ("Launch" issue, early 2008), Ted Neward answers the "why use F#" question as follows:

Functional languages help developers support concurrency by encouraging immutable data structures that can be passed between threads and machines without having to worry about thread safety.

The underlying assumption is that F# "encourages" immutable data. This may be the case, but does this "encouraging" really work?

Give It Up For Immutable Data!

In the paragraphs below, we will find that the if you want your data to be really immutable, you cannot use:

  • Arrays
  • Dictionaries
  • Any .NET classes with mutable members, such as Windows Forms, WCF proxies, ASP.NET pages, XML parsers, etc., etc.

So, the $1M queastion is

How much mutable data a typical F# program would deal with?

The answer is, of course, "it depends". It depends on the task at hand, on the programming habits and the libraries we use. I believe that in the current state of the language any real F# program will contain lots of mutable data.

Myth #1. In F# All Data Is Immutable

Well, this is not really a myth, since very few people believe it. F# explicitly allows mutable data, and if something is allowed, people will use it. So, using immutable data in F# requires discipline, just as it does in C# ot Java.

Myth #2: You Must Use "mutable" Keyword To Make Things Mutable

This is definitely false, for variety of reasons:

  • Class members are mutable by default.
  • Classes are passed by reference. If your otherwise immutable object contains a reference to a class, it depends on mutable data.
  • F# Arrays are mutable classes.
  • Many other collections are mutable classes as well.

Mutable Arrays

Let's consider the following little piece of code:

type Record =
 {
   data : int array;
 }

No mutable keyword in sight, eh? Still, your data is mutable.

let first = {data=[|10;20|]}
let second = first
Console.WriteLine first.data.[0]  // prints 10
second.data.[0] <- 42           // mutable?!
Console.WriteLine first.data.[0] // prints 42

Note, that we did not use mutable even once. Not only we are able to change the data, the change also "contaminates" another object!!!

Immutable Arrays, Anyone?

Of course, one may say: don't use arrays, but then what is an alternative? What if I do have a relatively large uniform list of things that requires random access? E.g., I don't know, current rotating speeds of the 128 fans that cool down my shiny 65536-core CPU? There is some research into functional arrays, and they are incorporated into languages like Haskell, where AFAIR arrays are immutable. I also found a post about functional arrays in OCaml, but I am not sure whether it really works. In any case, F# did not bother with functional arrays, and it uses standard .NET arrays.

Other Mutable Collections

F# implemented quite beautiful immutable set, but it pretty much ends there. Even the books that are supposed to demonstrate best practices use mutable structures. E.g., in "Expert F#" Don Syme himself uses mutable dictionary to store intermediate results of computations. Yes, this dictionary would be local to a function, and thus most likely is not a thread-safety issue, but I fail to see how it is radically different from C# or Java.

Sequences

Sequences can be safely passed between threads, unless they use mutable state to produce the items. But sequences have other unpleasant properties: they cannot be tail-recursed into (no "tail" operator), and they cannot be matched against. This may seem irrelevant, but the lack of tail-recursion sometimes paints you into a corner and forces to use a while loop on the enumerator, as in this F# library code:

module Seq = ...
    let tryfind f (ie :> IEnumerable<'a>)  = 
        use e = ie.GetEnumerator()
        let mutable res = None 
        while (Option.is_none res && e.MoveNext()) do
          let c = e.Current in if f c then res <- Some(c)
        done;
        res

And enumerator, my friends, is mutable data. Also note mutable res variable. If F# library has to do it, you may also have to do it under different circumstances.

Myth #3: Most Data In F# Is Immutable

F# is a port of OCaml to .NET. It is the power of .NET libraries that makes F# commercially viable. .NET libraries penetrate the core of the language: IEnumerable, arrays, The trouble is, most .NET library objects rely on mutable state: XML parsers, ASP.NET pages, Windows Forms, WCF proxies. It might be possible, but is definitely very difficult to use them from a functional program and avoid relying on mutable state yourself. Therefore, it would not happen, since people tend to take the path of least resistance.

Summary

In theory, F# encourages immutable data. In practice holding on to it requires strong discipline, almost as strong as in C# in Java. Any real world F# program would contain significant amount of mutable state.

F# definitely has attractive properties and interesting ideas, but in my view the "immutable data" point has been heavily oversold.