Intuitively, we think of stacks as being those things on which we can push values, whose top value is the thing last pushed, and that if we pop a stack onto which we've pushed value, we have the original stack.
This intuition can be cast as an abstract algebra,
with Push and Pop representing any computations on a data object called a Stack involving ELements:
algrebra Stack
{
data Stack;
data Element;
Empty() -> Stack;
Push(Stack,Element) -> Stack;
Pop(Stack) -> Stack;
Top(Stack) -> Element;
axiom Top(Push(s,e))==e;
axiom Pop(Push(s,e))==s;
axiom Pop(Empty())==undefined;
}
What this says is that if you can find entities in your system,
- some of which you claim are Stack types
- some of which you claim are Elements,
- some which are functions that you claim are Push,
- some which are functions that you claim are Pop, Top, Empty, etc.
then the signatures of the various functions match those in the algebra,
and that if you apply the various functions, they will behave as
the axioms specify. (The entities you select are "isomorphic"
to the algebra).
The advantage of this perspective is that it says nothing about the
implementation of the various entities, while still capturing the essence.
This algebra covers the various artifacts dicussed in other answers;
it should be clear that a linear storage area used as a stack is a stack,
that a linked list used a stack is stack, that a deque used one end is a stack,
that a series of disk blocks used as a stack is a stack,...
What's really cool is that you can rename all the data types and the functions
inside the stack algebra, and yet still recognize a stack because renaming
has no effect on isomorphisms (because consistent renaming is just another isomorphism,
and isomorphisms compose to product isomorphisms). Anything that matches
this specification is a stack!
The fact that the function names in the implementation can be anything and
yet still match, and that we can rename the abstract algebra function names
to anything, and still match, allows us, by convention, to give the abstact
algebra functions names the ones we consider to be representative. "Push"
and "pop" are the ones chosen by convention.
So I'd say, you can call your name your implementation functions anything you
like, but call them Push and Pop, if their actions realize this algebra.
So, one can define a Stack by a formal spec. You can define any other data structure
this way, too.
Too bad we don't do more of this in documenting real code.