As many long time readers know, I am an enthusiast of the F# programming language. I make no apologies for the fact that, if you are developing software on the .NET platform, F# is one of the better choices you can make for numerous reasons. It is one of the reasons I proudly contributed as a co-author to the book, Professional F# 2.0, which is being published by Wrox in October.
Some of the oft cited benefits of F# are that, to distill them quickly, it is good at doing intensely mathematical operations, it is built for parallelism, and it is good at helping define domain specific languages. Those benefits are so often cited by speakers on the F# speaker circuit that they pretty much seem cliche to me at this point (note, yours truly is proud to call himself a member of said circuit, and often gives this talk!) As great as these features are, there are a couple features, that in my more mundane F# experiences, seem to stand out as things that “save my ass”, for lack of a better phrase, more often than not.
Advantage 1: Near Eradication of the Evil NullReferenceException
The first feature I am most dutifully grateful for is that when working with F#, you almost never deal with the concept of null. A side effect of being “immutable by default” is that the pattern of “lets leave this thing uninitialized until I use it later, then forget I didn’t initialize it when I try to use it” mostly goes away. In other words, immutable code almost never has a reason to be null, therefore, no null pointer exceptions if you stick to immutable structures.
How often do you see this pattern in a legacy code base:
if (thisThing != null && thisThing.AndThatThing != null)
… or worse, deeply similar nested examples? When I am doing code archaeology, sometimes even on more recent code bases, I usually spot this kind of code as places where:
a.) Some very careful programmer is doing null checks to make sure she does not get a null pointer exception
… or, more commonly…
b.) Someone fixed one or more NullReferenceExceptions they were getting.
The only time you routinely deal with the concept of null in F#, typically, is when doing interop work, likely someone else’s ill-initialized C# code. Of course, one may wonder how one represents the idea of something actually being “missing”, that is, something roughly analagous to null, in F# code. Well, that is where the option comes to the rescue. If, for example, you have a concept of weather, you might have this:
type Weather =
Skies : Sky
Precip : Some(Precipitation) // Precip : Precipitation option will also work
In this example, weather will always have a sky, but only might have some precipitation. If something is optional, you say so, which means that you can have the value of Precip either be Some(somePrecipValue) or None. For C# programmers, this is roughly analogous to Nullable<T>, only it applies to objects, not just value types. What this does is force the programmer to state which objects can be in a state of “absence” by exception. In the same way that a database design becomes more robust when you make more of your fields non-nullable, software becomes more robust and less prone to bugs when fewer things are “optional” as well.
Advantage 2: Your Entire Domain in One Page of Code
The second advantage – at least in my mind, is that unlike C# and Java – the lack of syntax noise in F# means that nobody uses the “one class per file” rule that is conventional in the world of most mainstream programming languages. The nice thing about this is that, frequently, you can put a reasonably complex entire domain model on one printed page of code.
One pattern I use quite a bit is that I put the set of relationships between types in one file, along with common functions between elements. If I need to extend the domain in any way – such as adding later a conversion function from a domain to a viewmodel or something like that, I put that in a separate file, where I can write extension methods that adapt the domain to whatever I need it to be adapted to.
Extension methods? What if I need to use a private member to extend the domain? Well – that does beg a question – when do functional programmers use private members? I can only vouch for myself, but seldom do I feel the need in F# programs to hide anything. Think about why we ever need encapsulation – it is usually to stop outsiders from changing the member variables inside our class. If there is nothing that varies – as is the case with a system built using immutable constructs, then there is less need for such encapsulation. I may have a private member somewhere to hide an implementation detail, but even that tends not to be a mainstream case that I would ever use in an extension scenario (i.e. projecting a domain object to a viewmodel).
The overall advantage, in the way F# is written, is that you can have all of your related concerns on a single page of code in most systems. This ability to “print out and study the domain in the loo” leads to a subtle, but important reason, why F# is good for expressing domains.
Is it for Everything?
No – not by a long-shot. But more and more, I am seeing F# as useful for many things beyond the traditional math, science, and obviously parallel type applications that functional languages are traditionally considered useful for. Specifically, the more I use it in MVC and REST style applications, the more it grows on me. Especially when I am working with Java or C# code, and fixing someone else’s NullReferenceExceptions!