An easier way of writing conditional code

I love attending code retreats. It’s an extremely efficient way to learn new things, though the people you pair with and the exercises you practice. And since keeping up with the newest thing is essential to a programmer, what better way to expand your knowledge is there than to let your creativity loose writing code in a different manner than the one you do every day?

What is a code kata?

A code kata is an exercise in programming which helps hone your skills through practice and repetition. Usually at code retreats, you pair with a different partner for each kata and you try to solve them by applying different pair programming techniques. Definitely my favorite kata so far is “Use no conditional blocks in your code”.

Why are conditional statements “bad”?

Conditional structures in C# include the if and switch statements. Although they are essential to any complex application, an excess in using them might make the code unreadable, hard to maintain and/or extend with new functionality.

Conway’s Game of Life

Let’s take the classic code retreat problem, Conway’s Game of Life. Here are the basic rules:

  1. Any live cell with fewer than two live neighbours dies, as if caused by under-population.
  2. Any live cell with two or three live neighbours lives on to the next generation.
  3. Any live cell with more than three live neighbours dies, as if by overcrowding.
  4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.

For now, let’s assume that for each cell in the game we know the number of its neighbours and if it’s dead or not.

public class InitialCell
{
    public int Neighbours { get; set;}
    public bool IsDead { get; set;}
}

Implementing the rules with conditional statements, we would write something like the following. You can image that if the game were to have more rules implemented, the chain on if statements would become very long and we’d run into the above mentioned problems. Same goes for a switch implementation.

 public bool CellSurvives()
 {
     if (this.Neighbours < 2)
     {
         //Underpopulation
         return false;
     }
     else if (this.Neighbours > 4)
     {
         //Overpopulation
         return false;
     }
     else if(this.Neighbours == 3 && this.IsDead)
     {
         //Survives by reproduction to next iteration
         return true;
     }
     else
     {
         //Survives to next iteration
         return true;
     }
 }

An easier way with LINQ and Func

An easier way to implement this rules would be by using C# language features like LINQ and Func. A Func is a type of delegate that encapsulates a method that has one or more parameters and returns a value of the type specified by its last parameter. Basically, a Func is an Action that can return a value.

We can rewrite the game rules like so:

 Func<Cell, bool> IsUnderpopulated = cell => cell.Neighbours < 2;
 Func<Cell, bool> IsOverpopulated = cell => cell.Neighbours > 4;
 Func<Cell, bool> CannotReproduce = cell => cell.IsDead ? (cell.Neighbours == 3 ? false : true) : false

 Rules.Add(IsUnderpopulated, IsOverpopulated, CannotReproduce);

A cell will survive to the next iteration if all the rules we defined will return false: the cell will survived if it’s not under/overpopulated or it the reproduction condition is met. Using LINQ, we can verify them like so:

 public bool CellSurvives()
 {
     return Rules.All (rule => rule(this) == false);
 }

Validating the two implementations with Unit Testing

We can verify that both ways of implementing The Game Of Life are valid by writing some unit tests. Using NUnitLite, here are some that I came up with:

[Test ()]
 public void CellWithTwoNeighboursSurvives ()
 {
     Cell cell = new Cell ();
     cell.Neighbours = 2;

     Assert.IsTrue (cell.CellSurvives());
 }

[Test ()]
 public void DeadCellWithThreeNeighboursSurvives ()
 {
     Cell cell = new Cell ();
     cell.Neighbours = 3;
     cell.IsDead = true;

     Assert.IsTrue (cell.CellSurvives());
 }

More tests and all the code presented is available on GitHub. Of course, this is not the only way to avoid conditional statements and other methods are available. Whichever one you chose,  the ultimate goal here is to improve skill and have that mindset which allows you to see that things can always be improved.

Leave a comment