I was reading through Juval Löwy's Programming WCF Services book and wondering if I should do a series of WCF blog posts in F# based on Löwy's book when I ran into a common construct found in C# programs. That construct looks something like the following C# code:
public static void MyMethod(String oldstuff, String newstuff, bool flag)
{
if (oldstuff == null)
throw new Exception("oldstuff is null!");
if (newstuff == null) {
DoSomething("Default");
return;
}
if (flag == false) {
DoSomething(oldstuff);
return;
}
DoSomething(newstuff);
}
This is a construct that I oftened have used in the past and have never thought about it much. But when you translate the above code directly into F#, it becomes a lot more verbose because F# requires you to implement the then clause. A direct translation to F# as follows:
let mymethod oldstuff newstuff flag =
if oldstuff = null then
raise (new Exception("oldstuff is null!"))
else
if newstuff = null then
DoSomething("Default")
else
if flag = false then
DoSomething(oldstuff)
else
DoSomething(newstuff)
If I had a lot of these if-then-else statements in my C# method, then my F# version would disappear off the screen to the right if I tried to implement it by direct translation. I thought about how I could implement this in F# and came up with this following possibility:
let revised_mymethod oldstuff newstuff flag =
let (_,action) =
[(oldstuff=null, lazy (raise (new Exception("oldstuff is null!"))));
(newstuff=null, lazy (DoSomething("Default")));
(flag=false, lazy (DoSomething(oldstuff)));
(flag=true, lazy (DoSomething(newstuff)))]
|> List.filter fst
|> List.head
action.Force()
Rewriting the C# code in this fashion makes me think of rules engines and after refactoring out some common code, I could rewrite the above F# code as follows:
let followrules (xs:(bool*Lazy<unit>) list) =
(xs |> List.filter fst |> List.head |> snd).Force()
let revised_mymethod2 oldstuff newstuff flag =
[(oldstuff=null , lazy (raise (new Exception("oldstuff is null!"))));
(newstuff=null, lazy (DoSomething("Default")));
(flag=false, lazy (DoSomething(oldstuff)));
(flag=true, lazy (DoSomething(newstuff)))]
|> followrules
With this new construct, I can easily re-arrange the order of evaluation, add or remove new conditions. This new construct just seems to have more advantages than the old if-then-else construct in F#.