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:
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
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.