Stack ’em up!

OK, clearly I have been remiss in my bloging duties and owe you all some code.  To be fair, it’s because I’m head down developing a brand new platform that will form the basis of our future products and it really has been all go.

One of the most fundamental structures in programming languages is the stack.  It’s an insanely useful structure, particularly for analysing hierarchical data, but also for removing recursion from code (because recursion is oft times bad).

C# has a handy generic 

Stack

  class – which can be used like so-

Stack<int> stack = new Stack<int>();
stack.Push(1);
stack.Push(2);
Console.WriteLine(stack.Pop()); // Outputs: 2
Console.WriteLine(stack.Pop()); // Outputs: 1

Basically, you push things onto the top of the stack, and pop them off later.  It’s amazing what you can do with such a simple concept, but that’s not the topic of this post.

When you start doing more complex operations, you often find you want to put quite a bit of data onto the stack, rather than just a simple class.  I often find, in this particular scenario, it’s time to create a custom class/struct to hold the data.  However, sometimes, you just need something really simple.  It’s at times like those our old friend the Tuple comes in handy.  However, the code starts looking really unwieldy alarmingly quickly-

Stack<Tuple<int, string, bool>> stack = new Stack<Tuple<int, string, bool>>();
stack.Push(new Tuple<int, string, bool>(1, "One", false));
stack.Push(new Tuple<int, string, bool>(2, "Two", true));

Tuple<int, string, bool> frame = stack.Pop();
// Outputs: 2, Two, True
Console.WriteLine(string.Format("{0}, {1}, {2}", 
    frame.Item1,
    frame.Item2,
    frame.Item3));

frame = stack.Pop();
// Outputs: 1, One, False
Console.WriteLine(string.Format("{0}, {1}, {2}", 
    frame.Item1,
    frame.Item2,
    frame.Item3));

We can solve this really easily though, by extending

Stack

  to support multiple values:

public class Stack<T1, T2> : Stack<Tuple<T1, T2>>
{
    public void Push(T1 item1, T2 item2)
    {
        Push(new Tuple<T1, T2>(item1, item2));
    }
}

public class Stack<T1, T2, T3> : Stack<Tuple<T1, T2, T3>>
{
    public void Push(T1 item1, T2 item2, T3 item3)
    {
        Push(new Tuple<T1, T2, T3>(item1, item2, item3));
    }
}
public class Stack<T1, T2, T3, T4> : Stack<Tuple<T1, T2, T3, T4>>
{
    public void Push(T1 item1, T2 item2, T3 item3, T4 item4)
    {
        Push(new Tuple<T1, T2, T3, T4>(item1, item2, item3, item4));
    }
}
public class Stack<T1, T2, T3, T4, T5> : Stack<Tuple<T1, T2, T3, T4, T5>>
{
    public void Push(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5)
    {
        Push(new Tuple<T1, T2, T3, T4, T5>(item1, item2, item3, item4, item5));
    }
}
public class Stack<T1, T2, T3, T4, T5, T6> : Stack<Tuple<T1, T2, T3, T4, T5, T6>>
{
    public void Push(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6)
    {
        Push(new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3, item4, item5, item6));
    }
}
public class Stack<T1, T2, T3, T4, T5, T6, T7> : Stack<Tuple<T1, T2, T3, T4, T5, T6, T7>>
{
    public void Push(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7)
    {
        Push(new Tuple<T1, T2, T3, T4, T5, T6, T7>(item1, item2, item3, item4, item5, item6, item7));
    }
}
public class Stack<T1, T2, T3, T4, T5, T6, T7, TRest> : Stack<Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>>
{
    public void Push(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest)
    {
        Push(new Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>(item1, item2, item3, item4, item5, item6, item7, rest));
    }
}

Now we can write the same code in a much nicer way:

Stack<int, string, bool> stack = new Stack<int, string, bool>();
stack.Push(1, "One", false);
stack.Push(2, "Two", true);

var frame = stack.Pop();
// Outputs: 2, Two, True
Console.WriteLine(string.Format("{0}, {1}, {2}", 
    frame.Item1,
    frame.Item2,
    frame.Item3));

frame = stack.Pop();
// Outputs: 1, One, False
Console.WriteLine(string.Format("{0}, {1}, {2}", 
    frame.Item1,
    frame.Item2,
    frame.Item3));

Simple, but very effective.  Let me know if it helps you out in the comments below.

Related Images: