Throw If Away

What If?

In all programming languages there are concepts of control flow. Control flow simply means the path the code will take when executed based on conditions. One of the most common mechanisms used for control flow is the infamous “if” keyword. In all the languages I have worked with there is a concept of “if”. AS I’m sure you know, “if” denotes a condition that will be met before some code is executed.

The “if” expression

In C style syntax languages its usually “if” is followed by some boolean expression that evaluates to true or false typically followed by a body wrapped in curly braces {}. For example:

public void DoBarIf(foo)
{
    if(foo == true)
    {
        bar();
    }
    bar2();
}

Other times the same thing can be expressed like this:

public void DoBarIf(foo)
{
    if(foo == true)
        bar();
    bar2();
}

In this case white space, more specifically indention is relied upon to determine what code gets executed.
In both cases the “bar2” method will be executed following the the if condition. There is usually some debate on most teams about which style is acceptable in C style languages. Which do you prefer? Personally when writing code with curly braces, I prefer the curly braces. When writing in languages that don’t have curly braces there is nothing to argue.

In F# you can write similar code if you really want to. It would look something like this:

let doBarIf foo =
    if foo = true then bar
    bar2

In my opinion this is ok, but F# has a very wonderful feature that I have come to abuse, that makes F# code look like F# code. Its called pattern matching. Using it in such a simple case as this maybe overkill, but I’ll show it to you anyway.

let doBarIf foo =
    match foo with
    | true -> bar
    | false -> ()
    bar2

The syntax as shown above starts with the work match followed by a value followed by with. The next few lines are indented and start with a “|” followed by each expected condition that the value can be in. In this case since foo is a boolean value the only possible evaluations of foo are true and false.

The “->” characters in a pattern match simply states execute this logic when the previous condition is met.
So when foo = true, bar will be executed. When foo = false, nothing gets executed. That “()” symbol is representative of what is known as a “unit” in F#. It is just an empty expression body. You can learn more about unit in other posts.

I’m sure you noticed “bar2” after the match expression completed. Since its indented the same amount as “match” it will get executed regardless of the value of foo. It is simply the next command in the flow of control.

There is one other important concept in this example that I need to convey. You might have noticed in the F# example we handled both the true and the false conditions. The compiler would have warned us if we didn’t have both patterns matched because it knows either branch of logic could be executed. In C style languages when you don’t execute any logic in the opposite boolean condition then you don’t typically specify it.

If we did the code would like pretty silly. For example:

public void DoBarIf(foo)
{
    if(foo == true)
    {
        bar();
    }
    if(foo == false)
    {
        bar2();
    }
}

There is just an empty code block following the false check. Which explicit, most programmers would likely say these are wasted lines. In F# on the other hand, I think most would agree specifying both cases would be expected.

The “if else” expression

If we were to want to execute something different logic when foo is false you know what that would look like in a C style language, but typically wouldn’t express it as two separate if conditions you would use an if else expression like:

public void DoBarIf(foo)
{
    if(foo == true)
    {
        bar();
    }
    else
    {
        bar3();
    }
    bar2();
}

The same type of expression is also possible in F#, you can use the else keyword as you would expect.

let doBarIf foo =
    if foo = true
    then bar
    else bar3
    bar2

This is in my opinion quite ugly. I prefer to use pattern matching for this. In this case is pretty similar to our previous version. It would look like

let doBarIf foo =
    match foo with
    | true -> bar
    | _ -> bar3
    bar2

There is a subtle difference here. In this example we have replaced the false condition with a _.
In pattern matching the _ character is a catch all or wild card. In this case it behaves like an else. If there is a case where foo doesn’t equal true then _ will match the expression and bar3 will be executed.

The Switch Statement

In C# we use a case statement if there are more than a small number of paths that can be taken in code. Typically if there are more than 2 or 3 scenarios you will likely want to think about using a switch statement.
Here is a simple example of a method switch statement.

public void Foo(string bar)
{
    switch(bar)
    {
       case "1":
       {
           Console.Writeline("bar is 1");
           break;
       }
       case "2":
       {
           Console.Writeline("bar is 2");
           break;
       }
       case "3":
       {
           Console.Writeline("bar is 3");
           break;
       }
       default:
       case "4":
       {
           Console.Writeline("bar is 4");
           break;
       }
    }
}

The previous example does executes a different set of logic based on the value of bar. The logic in this example is quite trivial, but imagine a different workflow in each case. Including the curly braces each condition takes at a minimum 5 lines of code. Luckily the same type of logic can be executed in a single line per condition if F#. You have already seen this with the if, and if else conditions. It uses the exact same syntax as before and its easy to remember. In c# you probably often for get the switch syntax and more often than not the break after each case. Say good bye to those breaks and extra curly braces.

Here is the F# version of the switch statement above.

let foo bar =
    match bar with
    | "1" -> printfn "1"
    | "2" -> printfn "2"
    | "3" -> printfn "3"
    | _ -> printfn "4" 

While F# does support if else syntax. If you can’t call if else in a single line and have it still be readable you probably should use the pattern matching syntax.

Spread The Word
Adam.Wright
 

Adam Wright is a technologist specializing in software development using Microsoft technologies.

Click Here to Leave a Comment Below 0 comments