๐ŸŽ“ A1Learner
๐Ÿ”
0 of 37 lessons completed

Dart Generic Stack

A stack is a last-in, first-out collection. A generic stack holds one element type chosen by the caller.

Push and pop with strings

Three names go onto the stack. They come back off in reverse order.

class Stack<T> {
  final List<T> _items = [];

  void push(T item) {
    _items.add(item);
  }

  T? pop() {
    if (_items.isEmpty) {
      return null;
    }
    return _items.removeLast();
  }

  T? peek() {
    if (_items.isEmpty) {
      return null;
    }
    return _items[_items.length - 1];
  }

  bool get isEmpty {
    return _items.isEmpty;
  }
}

void main() {
  var stack = Stack<String>();
  stack.push('alpha');
  stack.push('beta');
  stack.push('gamma');
  print('top: ${stack.peek()}');
  print(stack.pop());
  print(stack.pop());
  print(stack.pop());
}

An int stack

The same class now holds ints. No new class was written for the new element type.

class Stack<T> {
  final List<T> _items = [];

  void push(T item) {
    _items.add(item);
  }

  T? pop() {
    if (_items.isEmpty) {
      return null;
    }
    return _items.removeLast();
  }

  T? peek() {
    if (_items.isEmpty) {
      return null;
    }
    return _items[_items.length - 1];
  }

  bool get isEmpty {
    return _items.isEmpty;
  }
}

void main() {
  var stack = Stack<int>();
  stack.push(1);
  stack.push(2);
  stack.push(3);
  print(stack.pop());
  print(stack.pop());
  print(stack.pop());
}

Peek and isEmpty

An empty stack peeks as null. After one push, peek shows the value and isEmpty turns false.

class Stack<T> {
  final List<T> _items = [];

  void push(T item) {
    _items.add(item);
  }

  T? pop() {
    if (_items.isEmpty) {
      return null;
    }
    return _items.removeLast();
  }

  T? peek() {
    if (_items.isEmpty) {
      return null;
    }
    return _items[_items.length - 1];
  }

  bool get isEmpty {
    return _items.isEmpty;
  }
}

void main() {
  var stack = Stack<String>();
  print('isEmpty: ${stack.isEmpty}');
  print('peek: ${stack.peek()}');
  stack.push('x');
  print('peek: ${stack.peek()}');
  print('isEmpty: ${stack.isEmpty}');
}

Example

class Stack<T> {
  final List<T> _items = [];

  void push(T item) {
    _items.add(item);
  }

  T? pop() {
    if (_items.isEmpty) {
      return null;
    }
    return _items.removeLast();
  }

  T? peek() {
    if (_items.isEmpty) {
      return null;
    }
    return _items[_items.length - 1];
  }

  bool get isEmpty {
    return _items.isEmpty;
  }

  int get length {
    return _items.length;
  }
}

void main() {
  var tasks = Stack<String>();
  tasks.push('email');
  tasks.push('report');
  print('next: ${tasks.pop()}');
  print('next: ${tasks.pop()}');
  print('left: ${tasks.length}');
}

Key points

  • push adds a value to the top of the stack.
  • pop removes the top value and returns it.
  • peek reads the top value without removing it.
  • pop and peek return T? here, so an empty stack gives null instead of an error.
  • The backing list stays private, so outside code cannot disturb the order.

In this example, two task names go onto the stack. pop takes report first because it went on last. email follows, and the length reads 0 once both are gone.

Note

the same Stack class serves strings, numbers, and any other single type.

Try it Yourself

Edit the code, then press Run.

Running is simulated ยท DartPad

Exercise

What does pop return on an empty stack in this lesson?