Time for another adventure in F#, covering some of the basics of functional programming and F# in particular. Today we'll manage to look more at regular .NET integration and .NET programming. With the previous efforts, we've looked more at
functional programming and in turn F# specific things, but want to show that you can do anything normally in F# that you can in C#. To me, F# is the perfect all-purpose language because it can do a lot of the things C# can do, but in turn, F# can do things much more elegantly than C# can, such as
Pattern Matching.
Where We Are
Before we begin today, let's catch up to where we are today:
Today's topic will be covering imperative and object oriented programming in F#. There is a lot to cover, so let's get started. But there are a few administrative things to get out of the way first.
Learning F# ala Ted Neward?
Ted Neward recently announced on
DotNetRocks Episode 332 that he's in the process of creating a class for F# for
Pluralsight. That should be interesting to those who are interested in this series, as well as F# in general. Right now the community is rather small, so efforts like this should be rather rewarding I would hope. Ted's a pretty brilliant guy, so I'd imagine only the best. I'm hoping more details come out soon.
Pattern Matching in C#
Part of this series is intended to bring such concepts as Pattern Matching,
Currying and other Functional Programming concepts to the C# developer. After all, the more C# language evolves, the more it seems to fall into the Functional Programming category. In previous posts, I showed how to relate currying to C# and it was less elegant than F# to say the least.
But, let's look at Pattern Matching.
Bart De Smet has been posting recently on his blog about bringing the beauty of pattern matching to C#. So far it's been a good six posts into it and I urge you to go ahead and take a look at this series.
But when you read the series, it's all about getting into the low level and compiling expression trees to make the same simple beauty that is F#. Sure, it can be done in C#, but nowhere near as elegant. Performance is another issue that comes to mind with these.
Imperative Programming in F#
This section I'll lay out some of the basics of imperative style programming before I get into the full object oriented approach to programming. So, we'll cover just a few topics and then I'll feel comfortable moving onto the real parts of creating classes and such. We'll cover such things as void types and mutability in this section.
The unit Type
One of the first things I forgot to mention when describing F# functions and values in the unit type. Think of this as the void type in C# that you are used to. It's the type that doesn't accept or return a value. First, let's look at the typical C# program with the void type for Hello World.
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World");
}
}
Now, let's go ahead and look at it from the F# perspective.
#light
let main() =
printfn "Hello World"
main()
As you will see when you hover over our code is that it is a unit type. That in itself isn't all that interesting. But, what we'll run into is problems when functions return a value, but we're not all that interested in them. What happens? Well, F# will complain that your return value isn't compatible with the unit type, which is essentially true. So, how do you get around that? Let's walk through a simple unit test of a Stack written in F# and unit testing with the
xUnit.net framework.
#light
#R @"D:\Tools\xunit-build-1252\xunit.dll"
open System
open System.Collections.Generic
open Xunit
type Stack<'t> = class
val elements : LinkedList<'t>
new() = { elements = new LinkedList<'t>() }
member x.IsEmpty
with get() = x.elements.Count = 0
member x.Push element =
x.elements.AddFirst(element:'t)
member x.Top
with get() =
if x.elements.Count = 0 then
raise (InvalidOperationException("cannot top an empty stack"))
x.elements.First.Value
member x.Pop() =
let top = x.Top
x.elements.RemoveFirst()
top
end
[<Fact>]
let PopEmpty () =
let stack = new Stack<string>()
Assert.Throws<InvalidOperationException>(fun () -> stack.Pop() |> ignore )
The real interesting part you should pay attention to is the last line. As you can see, I am using the forward operator to indicate that I really don't care what the function returns, just that I'm interested in that it executes. This is most likely during such functions that have some sort of side effect to them. I could also use the ignore function instead of the forward operator such as this:
[<Fact>]
let PopEmpty () =
let stack = new Stack<string>()
Assert.Throws<InvalidOperationException>(fun () -> ignore(stack.Pop()) )
This is very helpful in these cases where we really don't care about the return value, instead want to mutate the state of our given object, such as removing a value from a collection and so on.
Mutables
As I said in many posts before, by default all "variables" by which I mean values in F# are immutable. This is a standard in functional programming and all in the ML family. You can easily redefine a value by using the let keyword, but not actually mutate its state. But, since F# is a multi-purpose language on the .NET platform, mutable state can be had. To take advantage of this, mark your value as mutable. Then to change the value, just use the <- operator to reassign the value. Below is a simple example of this:
#light
let mutable answer = 42
printfn "Answer is %i" answer
answer <- 8
printfn "Answer is %i" answer
A key difference from the reassignment is that you cannot change the value type. Whereas I can redefine answer by keep using the let keyword, I can only keep my answer in this above example of the int type.
This can also apply to record types as well where you can change the fields. In the last installment, we talked about record types. Well, by default there as well, the fields for the record type are immutable. But, as with before, that can be changed. I of course like to caution people that mutable state takes a lot of the value proposition away from the side effect free programming that you gain with F# by default. But, nevertheless, you can still do it as noted below:
#light
type Person = { FirstName : string; mutable LastName : string; mutable IsMarried : bool }
let friend = { FirstName = "Courtney"; LastName = "Cox"; IsMarried = false }
friend.LastName <- "Cox-Arquette"
friend.IsMarried <- true
What I was able to do was define a Person record and change a couple of fields while using the <- operator and defining the fields as mutable. Yes, I could have used some scientific calculation or something, but this was easy.
Reference Cells
The last thing I want to touch on in this post is reference cells. You can think of these much as pointers in other languages or reference types. These of course can be of any type. The idea behind using these is to make updating fields as easy as possible. As with mutable fields, you cannot change the type once it has been assigned. To use these, you need to remember three basic operators
- ref - Allocates a reference cell
- := - Mutates a reference cell
- ! - Reads the reference cell
Below is a quick example of mutation through reference cells:
#light
let x = ref 2
x := !x + 25
printfn "%i" !x
What the code example above lets me do is define a reference to the number 2. Then I can change that reference by reading the current x value and adding 25. Then I mutate the existing x value with the result.
Conclusion
This is just meant to be a brief overview to some imperative programming constructs that you might see in .NET, Java, C, C++ and so on. F# is a first class language all the way with constructs that support these things as well as your normal functional programming constructs. I hope we get to cover some of this at
ALT.NET Open Spaces, Seattle at some point because I'm sure a lot of people will be interested. Until next time...
Dave Laribee and
Jeremy Miller recently recorded an episode on
DotNetRocks and was just posted today. Episode 333 "It's the ALT.NET Show" can be found
here. It's a great show that explains
ALT.NET for those who may not really know what it is outside of some of the arguments on the
altdotnet mailing list. This includes discussions on open source frameworks, agile practices, refactoring and so on.
It's great to see the reaction from this show at least from my perspective. To see the job we're doing from
Josh Holmes,
Glenn Block, me and others from within to reach out and also present ideas and bridge the gaps. It's been very rewarding to be a part of that.
We're only just a few days away from
ALT.NET Open Spaces, Seattle. All of those who are attending should have received a notice of such this morning. I'll be arriving in Seattle on Thursday afternoon to help set up for the event so if anyone wants to hang out beforehand let me know.
Bringing It To The Community
Anyhow, this weekend I did my best to bring some of those ALT.NET practices to the
CMAP Code Camp and we had a pretty good turnout. This time I talked about refactoring to patterns, dependency injection and inversion of control containers. I'm hoping to do the same for the Northern Virginia Code Camp coming up on May 17th.
Brian Donahue has been rather successful doing so with the
Philly Code Camps as well. That reminds me that I'm coming up there in mid-May to do an F# session. Should be a fun time.