Skip to content

Fix stack-like behavior in 46-generic-types.md#1416

Open
lexidor wants to merge 1 commit intohhvm:mainfrom
lexidor:patch-4
Open

Fix stack-like behavior in 46-generic-types.md#1416
lexidor wants to merge 1 commit intohhvm:mainfrom
lexidor:patch-4

Conversation

@lexidor
Copy link
Copy Markdown
Contributor

@lexidor lexidor commented Feb 21, 2026

I copied this Stack into a project, and it yielded incorrect results.
I didn't spot that there are two Stacks in the documentation.
The Stack in the introduction is correct, so I propose we fix the example
by copying the VecStack<T> and trimming it down to be similar to the
Stack we had here before.

Seealso: #1171
Seealso: #1183

The previous implementation of Stack<T> from 46-generic-types.md yields incorrect results.
By copying the VecStack<T> from 01-introduction.md correct behavior is restored.

string(1) "a"
string(1) "b"
string(1) "a"
string(1) "b"
string(3) "---"
string(1) "a"
string(1) "b"
string(1) "c"
string(1) "d"

For the rationale on why the stack is implemented the way it is, see #1183.

With a reasonable use (pushing and popping 30000 elements) the Vec\take() variant takes 1.8 seconds, whereas the $this->stackPtr variant takes 8 milliseconds. This makes the difference between having a fast page render and a human perceivable slowdown when rendering. Yes, this stack is not used in this repository. However, it is not unthinkable that someone browsing the docs will copy-paste this stack into their own project. ...

use namespace HH\Lib\C;

<<__EntryPoint>>
function stack_demo(): void {
  $generics_46_stack = new StackAsDocumented<string>();

  $generics_46_stack->push('b');
  $generics_46_stack->push('a');
  var_dump($generics_46_stack->pop());
  var_dump($generics_46_stack->pop());

  $generics_46_stack->push('d');
  $generics_46_stack->push('c');
  var_dump($generics_46_stack->pop());
  var_dump($generics_46_stack->pop());

  var_dump('---');

  $generics_01_stack = new Stack<string>();

  $generics_01_stack->push('b');
  $generics_01_stack->push('a');
  var_dump($generics_01_stack->pop());
  var_dump($generics_01_stack->pop());

  $generics_01_stack->push('d');
  $generics_01_stack->push('c');
  var_dump($generics_01_stack->pop());
  var_dump($generics_01_stack->pop());
}

class StackUnderflowException extends Exception {}

class StackAsDocumented<T> {
  private vec<T> $stack;
  private int $stackPtr;

  public function __construct() {
    $this->stackPtr = 0;
    $this->stack = vec[];
  }

  public function push(T $value): void {
    $this->stack[] = $value;
    $this->stackPtr++;
  }

  public function pop(): T {
    if ($this->stackPtr > 0) {
      $this->stackPtr--;
      return $this->stack[$this->stackPtr];
    } else {
      throw new StackUnderflowException();
    }
  }
}

// Copied from VecStack<T> in https://docs.hhvm.com/hack/generics/introduction/
class Stack<T> {
  private vec<T> $stack = vec[];
  private int $stackPtr = -1;

  public function push(T $value): void {
    $this->stackPtr++;
    if (C\count($this->stack) === $this->stackPtr) {
      $this->stack[] = $value;
    } else {
      $this->stack[$this->stackPtr] = $value;
    }
  }

  public function pop(): T {
    if ($this->stackPtr >= 0) {
      $element = $this->stack[$this->stackPtr];
      $this->stack[$this->stackPtr] = $this->stack[0];
      $this->stackPtr--;
      return $element;
    } else {
      throw new StackUnderflowException();
    }
  }
}

@meta-cla meta-cla bot added the CLA Signed label Feb 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant