"""
Recall (a) Stack ADT:

Stack:
    # construct an empty Stack. 
    # will be called __init__ in python implementations
    empty_stack() --> Stack

    # make x the new "top" object
    push(x:object)    
        
    # remove and return the top element 
    # undefined if the stack is empty
    pop() --> object 
    
    is_empty() --> bool    
"""


class Stack:
    """A last-in, first-out (LIFO) stack of items"""

    # original version of __init__, which didn't allow for 
    # an easy to write __repr__
    #def __init__(self: 'Stack') -> None:
        #"""A new empty Stack."""
        #self._data = []
        
    def __init__(self: 'Stack', elements:list=None) -> None:
        """A new empty Stack."""
        if elements is not None:
            self._data = elements.copy()   # makes a copy of the list elements
        else:
            self._data = []

    def pop(self: 'Stack') -> object:
        """Remove and return the top item."""
        return self._data.pop()

    def is_empty(self: 'Stack') -> bool:
        """Return whether the stack is empty."""
        return self._data == []

    def push(self: 'Stack', o: object) -> None:
        """Place o on top of the stack."""
        self._data.append(o)

    def __eq__(self: 'Stack', other: 'Stack') -> bool:
        """Self is equivalent to other.
        >>> s1 = Stack()
        >>> s2 = Stack()
        >>> s1 == s2
        True
        >>> s1.push(7)
        >>> s1 == s2
        False
        >>> s2.push(7)
        >>> s1 == s2
        True
        """
        return isinstance(other,'Stack') and repr(self) == repr(other)

    def __repr__(self: 'Stack') -> str:
        """Represent this stack as a string."""
        # this is why we changed __init__
        return "Stack({0})".format(repr(self._data))
        

if __name__ == '__main__':
    import doctest
    doctest.testmod(verbose=True)
    