boustrophedonic

Thoughts on software and architecture

Implementing Tic-Tac-Toe Using State Classes

This post follows on from the previous one on union types, by showing how to use state classes to implement a Tic-Tac-Toe game (a.k.a. Noughts and Crosses here in the UK).

Background

I ran across two mentions of the game of Tic-Tac-Toe recently. First, in the excellent book “Professional Enterprise .NET” by Jon Arking and Scott Millett, chapter 4 describes using TDD for Tic-Tac-Toe.

Secondly, Tony Morris wrote a post a while back that he almost called “What to Solve Before Expecting Me to Take Your Opinions of Static Typing Seriously” in which he describes his disappointment that most programmers couldn’t implement a robust API for a trivial game like Tic-Tac-Toe.

An extremely robust API for a relatively trivial problem … was achieved by exploiting techniques available from static typing and functional programming.
[This] appears to be difficult for many programmers to reproduce.

Here is a paraphase of some of his requirements for the API:

  • If you write a function, I must be able to call it with the same arguments and always get the same results.
  • If I, as a client of your API, call one of your functions, I should always get a sensible result. Not null or an exception, etc.
  • If I call Move on a tic-tac-toe board, but the game has finished, I should get a compile-time error. In other words, calling move on inappropriate game states is disallowed by the types themselves.
  • If I call WhoWonOrDraw on a tic-tac-toe board, but the game hasn’t yet finished, I get a compile-time error.
  • It is not possible to play out of turn.

So, before reading on, think about how you might do this in C# – can you meet the challenge!

Union Types in C#

This post shows how to easily implement states in C# using a T4 template.

Background

I often run into situations where I need an object that has a number of alternate “states” or “choices”. The set of states must be treated as “one thing” for general manipulation, but on the other hand, each state will often have slightly different behavior from the other states.

Some examples:

  • A shopping cart might have states Empty, Active and Paid.
    • You can call “AddItem” but not “RemoveItem” on the Empty state
    • You can call “AddItem” and “RemoveItem” and also “Pay” on the Active state
    • You can’t do anything with the Paid state. Once paid, the cart is immutable.
  • A domain object such as Product might have states Valid and Invalid.
    • Only Valid objects can be saved to disk.
  • A game such as chess might have states WhiteToPlay, BlackToPlay and GameOver.
    • Only the GameOver state has a “Winner” method.
    • Only the other states have a “Play” method.

So given this common situation, what kinds of ways are there to implement these kinds of cases?

The inheritance based approach

The standard approach in a object-oriented language is to use inheritance. There is a class for each state, and each state inherits from a common base class or interface.

But where should the custom behavior live?

For example, in the shopping cart example, should the “RemoveItem” method be available at the interface level?

Approach 1: Define all possible actions at the interface level

Let’s say the “RemoveItem” method is available at the interface level, then the interface would look like this:

1
2
3
4
5
6
interface ICartState
{
    ICartState AddItem(Product product);
    ICartState RemoveItem(Product product);
    ICartState Pay(decimal amount);
}

Cart State - Approach 1

But what should the empty state implementation do with the methods that are not relevant? It can either throw an exception or ignore them, as shown below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class CartStateEmpty : ICartState
{
    public ICartState AddItem(Product product)
    {
        // implementation
    }

    public ICartState RemoveItem(Product product)
    {
        // throw not implemented exception or ignore
    }

    public ICartState Pay(decimal amount)
    {
        // throw not implemented exception or ignore
    }
}

Throwing an exception seems a bit drastic, and ignoring the call seems even worse. Is there another approach?

Semantic Strings in C#

This post shows how to easily implement simple types that wrap strings. This approach has a number of benefits:

  • The types have domain-specific meaning, so Email and ProductCode (say) are distinct value objects in a domain driven design).
  • The types cannot be mixed, and if they are, you get type errors at compile time, so Email values cannot be accidentally used where a ProductCode is expected.
  • The code itself can reveal whether absent values are allowed or not. So for example, a Product ProductCode property can never be null (and if you get it wrong you get errors at compile time), but a ProductCode? parameter could be null in the context of a database query .

String wrappers in F#

Learning functional programming (mainly F#) will change the way you think about writing C# code. There are lot of techniques in F# that, once you understand them, can be back-ported to C#.

In F#, for example, it is trivial to create simple one-liner types that represent simple domain value objects. Here’s the F# code:

1
2
3
type EmailAddress = EmailAddress of string
type ProductCode = ProductCode of string
type PhoneNumber = PhoneNumber of string

and so on.

Once created, values of these types are distinct and will cause compile time errors if you accidentally mix them up.

1
2
3
4
5
6
7
8
let email = EmailAddress "abc"
let productCode = ProductCode "abc"

// comparison causes error at compile time
let areEqual = (email = productCode)

// assignment causes error at compile time
let anEmail : EmailAddress  = productCode

(By the way, if you have Visual Studio 2010 or higher, you can test this for yourself in the F# interactive window. Just paste the code in and add a double semicolon at the end of each group)

So we get fine grained domain objects, plus extra type safety at compile time. What’s not to like!