jaywayco - Lost in IT Reverie

jaywayco

jconway
by jconway

Will F# ever be a first class citizen?

I have never had an opportunity to use F# in a commercial environment. I have been a developer in the .NET arena for 8 years and as yet have not been able to come up with a decent enough excuse to use it. I find F# fascinating and the more I read about it the more intrigued I am to see how it would stand up in a commercial .NET environment. But, like I say I have never had a reason strong enough to persuade myself to use it. Maybe I don't understand the pros and cons enough. Maybe I don't understand the practical benefits.

In this article im going to attempt to explore what are generally advertised as the pros of F#. From what I do understand, people sell it based upon the following features:

  1. Immutability by default
  2. Discriminated Unions
  3. Pattern Matching

Lets go through each one.

Immutability by default

Immutability is an object or value that cannot be mutated. A classic example in C# is the immutability of the string type. Because string is immutable if you are doing many concatenation operations it is beneficial to use the StringBuilder because the StringBuilder is mutable. To put it another way if you concatenated two immutable strings the result is a new immutable string. Changing a StringBuilder contents does not create a new StringBuilder so can be more memory efficient.

Mutability isn't always a good thing though. Immutability guarantees thread safety. If your value is immutable you can be sure that if there is another thread using the same value it cannot change the value from under you. Immutability is possible in C# but it is not implicit. I also means there is a lot of pattern code written to make types immutable.

So how does F# deal with keeping values immutable. It seems that the compiler can do most of the work. Lets use a simple example to illustrate this fact.

C#

private static void Main(string[] args)
{
    int i = new int();
    int j = i;
    i = 5;
    System.Console.WriteLine("i = {0}, j = {1}", i, j);
    System.Console.ReadLine();
}

Output:

i = 5, j = 0

Notice that we created a new int called i (weird syntax I know) we then create another new int and assign it the value that i has. Then we change the value of i. Is the result what you expected? I made j the same as i. Now I understand that int is a value type and is immutable and the line int j = I; is actually creating a new int and taking a copy of the value of i and changing i after this fact will have no impact on j whatsoever. But what if I was learning C# does this make sense? Maybe, maybe not. Now let's take a look at the equivalent in F#.

F#

[<EntryPoint>]
let main argv = 
    let i= 0 
    let j = i
    j <- 5 
    System.Console.WriteLine("i = {0}, j = {1}", i, j);
    System.Console.ReadLine();

This doesn't even build. The compiler tells me that j is immutable. The fact that j can't be changed after I've assigned it the same value as i is highlighted at compile time. The compiler is making sure that i == j. There is no doubt to any F# developer that i is immutable and that this operation is actually not allowed.

Discriminated Unions

Something that F# supports natively that C# doesn't is discriminating unions. They are similar to C++ union types with one key difference, they are type safe and immutable. See this post for a good introduction to F# discriminating unions.

Discriminating unions can be used to represent simple object hierarchies and the classic example is a Shape. From MSDN:

type Shape =
          // The value here is the radius.
        | Circle of float
          // The value here is the side length.
        | EquilateralTriangle of double
          // The value here is the side length.
        | Square of double
          // The values here are the height and width.
        | Rectangle of double * double

this doesn't really give us much. It gives us a more concise definition but the usage is the same.

another suggestion is that they can be used to represent heterogeneous data. This is interesting. This isn't easy in C# and it seems F# gives us a nice concise way to do this.

type LogEntry =        
        | Info of string
        | Debug of string
        | Error of string * string * System.Exception

You can see here that this Discriminating union could be used to model log entries in a log file. Although this is possible in C# the resulting code would be much more verbose.

Another suggestion is that discriminating unions can be used to represent tree structures. Again this isn't easy in C# and F# gives us a clear and concise syntax for modelling tree structures. From MSDN:

type Tree =
    | Tip
    | Node of int * Tree * Tree

Again this is very concise. It is possible to have this type of data structure in C# but it will be a lot more verbose.

So with discriminating unions we have a very powerful tool for representing heterogeneous data. But is it the best out there? Should I choose F# over some other technology? I'm not convinced yet.

Pattern Matching

Pattern matching in F# is, at first glance, similar to a switch statement in C#. Dig further though and it is much more powerful.

Pattern matching actually returns a result. The result can be of any type (as long as they are the same type). So given any value we can match on any match expression we like and return any data we like. Again from MSDN:

let pi = 3.141592654

let area myShape =
    match myShape with
    | Circle radius -> pi * radius * radius
    | EquilateralTriangle s -> (sqrt 3.0) / 4.0 * s * s
    | Square s -> s * s
    | Rectangle (h, w) -> h * w

    let radius = 15.0
    let myCircle = Circle(radius)
    printfn "Area of circle that has radius %f: %f" radius (area myCircle)

    let squareSide = 10.0
    let mySquare = Square(squareSide)
    printfn "Area of square that has side %f: %f" squareSide (area mySquare)

    let height, width = 5.0, 10.0
    let myRectangle = Rectangle(height, width)
    printfn "Area of rectangle that has height %f and width %f is %f" height width (area myRectangle)

We can also use pattern matching to work recursively with lists. From MSDN:

let list1 = [ 1; 2; 3; 4 ]

// This example uses a cons pattern and a list pattern. 
let rec printList l =
    match l with
    | head :: tail -> printf "%d " head; printList tail
    | [] -> printfn ""

C# has nothing that is as concise and powerful that is built in.

From my pretty shallow review of these "pros" you can easily see that discriminating unions and pattern matching would be very powerful tools for processing heterogeneous data. That married with implicit immutability enables a highly parallel solution.

So what kind of problem could this solve? Well as I touched on previously, it looks like it would be a good fit for defining data flows. And, because F# makes it safe for us to operate in a parallel environment, high volumes of data could be handled.

Objects

I understand that F# is a fully OO enabled language too. I can never see myself writing OO code with F#. It seems like F# has went out of its way to remove the need for hierarchies of objects. After all it is a functional language. It seems to me that F# is an OO language because it needs to integrate with the .NET platform, which is strongly OO. It doesn't make sense to write all of our code in F# so we will need an OO "interface" in our F# modules so that our chosen .NET OO code can make use of it properly.

I suppose you could look at this like another selling point. Are there any other functional languages that can slot into a largely OO architecture as easily as F# advertises it can?

So maybe the next time I am tasked with processing a large amount of heterogeneous data maybe now I can be confident enough to use F#. And, while I do I will be listening to this -

F# Song

Share the joy
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
If you like this blog follow me on twitter @jaywaycon or Google+




Comments

  1. Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>