Wednesday, September 17, 2008

Programming with State in F# (Part 1)

There is frequent talk these days about the use of state in programs--how to limit it and whether it should be used at all. The rising importance of concurrency and functional languages have a lot to do with this but state is hardly going to go away any time soon. For instance, Kent Beck writes favorably about state in his recent book, Implementation Patterns:
I think state is a valuable metaphor for us since our brains are structured and conditioned to deal with changing state. Single assignment or variableless programming forces us to discard too many effective thinking strategies to be an attractive choice.
Kent goes on to show his readers a set of patterns that can be used to manage and communicate state in a safe and effective manner. I agree that state is a valuable metaphor in programming but what is a programmer to do if they also see value in single assignment or "stateless" programming? I think F# offers the most compelling answer to this question and I'll explain why.

You declare a value in F# with the let keyword:
> let x = 1;;

val x : int
We can later retrieve the value, 1, using our identifier, x:
> x;;

val it : int = 1
Suppose, however, that we wanted to change the value assigned to x. We would use the assignment operator like so:
> x <- 2;;

x <- 2;;

stdin(13,1): error FS0027: This value is not mutable.
As you can see, identifiers are immutable by default in F#. Once declared, they cannot be changed. This behavior extends to more complex value types. Consider this example:
> open System.Drawing;;
> let p1 = new Point(0,0);;

val p1 : Point

> p1.X <- 1;;

p1.X <- 1;;

stdin(24,1): error FS0191: A value must be local and mutable in order to mutate
the contents of a value type, e.g. 'let mutable x = ...'.
Even though the X property of System.Drawing.Point is settable, F# treats our Point as if it is immutable. We can see how the default behavior of F# compels the programmer to limit his use of state; that's just the way that it should be. By contrast, it takes a lot of forethought to limit state in an imperative language.

You can opt-in to the use of state by using the mutable keyword:
> let mutable p2 = new Point(0,0);;

val mutable p2 : Point

> p2.X;;

val it : int = 0

> p2.X <- 1;;

val it : unit = ()

> p2.X;;

val it : int = 1
When you declare an identifier as mutable, you get a variable just like you may be used to in C# or Visual Basic. You can even change the reference entirely:
> p2 <- new Point(1,1);;

val it : unit = ()

> p2;;

val it : Point = {X=1,Y=1} {IsEmpty = false;
X = 1;
Y = 1;}
To conclude this post, I hope to have shown some very basic examples of how F# forces you to think about where you are using state and why. This is a very good thing and in my next post, we will explore the use of state in functions and types.

No comments: