Note: I may have chosen the wrong word in the title; perhaps I\'m really talking about polynomial growth here. See the benchmark
Is there a desperate need to have a distinction between the empty stack and the non-empty stack?
From a practical point of view you can't pop the value of an arbitrary stack without fully qualifying the type and after adding 1,000 values that's an insanely long type name.
Why not just do this:
public interface IImmutableStack
{
T Top { get; }
IImmutableStack Pop { get; }
IImmutableStack Push(T x);
}
public class ImmutableStack : IImmutableStack
{
private ImmutableStack(T top, IImmutableStack pop)
{
this.Top = top;
this.Pop = pop;
}
public T Top { get; private set; }
public IImmutableStack Pop { get; private set; }
public static IImmutableStack Push(T x)
{
return new ImmutableStack(x, null);
}
IImmutableStack IImmutableStack.Push(T x)
{
return new ImmutableStack(x, this);
}
}
You can pass around any IImmutableStack
and you only need to check for Pop == null
to know you've hit the end of the stack.
Otherwise this has the semantics you're trying to code without the performance penalty. I created a stack with 10,000,000 values in 1.873 seconds with this code.