# Visitor Pattern

## Problem

You have an AST (Abstract Syntax Tree) with different node types: NumberNode, AddNode, MultiplyNode. You need to add operations like printing and evaluation without modifying the node classes. Each new operation (type-checking, optimization, code generation) would require adding a method to every node class, violating the Open/Closed Principle.

## Solution

Define a **Visitor** interface with a `visit` method for each node type. Each node has an `accept(visitor)` method that calls the appropriate `visit` method on the visitor (double dispatch). New operations are added by creating new visitor classes — no node modification needed.

**Key participants:**
- **Visitor** — interface with `visitX()` for each element type
- **ConcreteVisitor** — PrintVisitor, EvalVisitor implementing operations
- **Element** — interface with `accept(visitor)`
- **ConcreteElement** — NumberNode, AddNode, MultiplyNode

## When to Use

- You need to add many unrelated operations to a stable class hierarchy
- The element hierarchy rarely changes but operations are added frequently
- An operation needs information from multiple element types (gathered during traversal)
- You want to avoid polluting element classes with unrelated methods

## When to Avoid

- The element hierarchy changes frequently — every new element requires updating all visitors
- Only one or two operations are needed — just add methods directly
- Elements have complex private state that visitors can't access
- Double dispatch feels unnatural for the team or language

## Pseudocode

```
INTERFACE Visitor:
    method visit_number(node: NumberNode)
    method visit_add(node: AddNode)
    method visit_multiply(node: MultiplyNode)

INTERFACE Node:
    method accept(visitor: Visitor)

CLASS NumberNode IMPLEMENTS Node:
    value
    method accept(visitor):
        visitor.visit_number(self)

CLASS AddNode IMPLEMENTS Node:
    left, right
    method accept(visitor):
        visitor.visit_add(self)

CLASS EvalVisitor IMPLEMENTS Visitor:
    result

    method visit_number(node):
        result = node.value

    method visit_add(node):
        node.left.accept(self)
        left_val = result
        node.right.accept(self)
        result = left_val + result
```

## Python

```python
from __future__ import annotations
from abc import ABC, abstractmethod


class Node(ABC):
    @abstractmethod
    def accept(self, visitor: Visitor) -> None:
        pass


class NumberNode(Node):
    def __init__(self, value: float) -> None:
        self.value = value

    def accept(self, visitor: Visitor) -> None:
        visitor.visit_number(self)


class AddNode(Node):
    def __init__(self, left: Node, right: Node) -> None:
        self.left = left
        self.right = right

    def accept(self, visitor: Visitor) -> None:
        visitor.visit_add(self)


class MultiplyNode(Node):
    def __init__(self, left: Node, right: Node) -> None:
        self.left = left
        self.right = right

    def accept(self, visitor: Visitor) -> None:
        visitor.visit_multiply(self)


class NegateNode(Node):
    def __init__(self, operand: Node) -> None:
        self.operand = operand

    def accept(self, visitor: Visitor) -> None:
        visitor.visit_negate(self)


class Visitor(ABC):
    @abstractmethod
    def visit_number(self, node: NumberNode) -> None:
        pass

    @abstractmethod
    def visit_add(self, node: AddNode) -> None:
        pass

    @abstractmethod
    def visit_multiply(self, node: MultiplyNode) -> None:
        pass

    @abstractmethod
    def visit_negate(self, node: NegateNode) -> None:
        pass


class PrintVisitor(Visitor):
    def __init__(self) -> None:
        self.result = ""

    def visit_number(self, node: NumberNode) -> None:
        self.result = str(node.value)

    def visit_add(self, node: AddNode) -> None:
        node.left.accept(self)
        left = self.result
        node.right.accept(self)
        right = self.result
        self.result = f"({left} + {right})"

    def visit_multiply(self, node: MultiplyNode) -> None:
        node.left.accept(self)
        left = self.result
        node.right.accept(self)
        right = self.result
        self.result = f"({left} * {right})"

    def visit_negate(self, node: NegateNode) -> None:
        node.operand.accept(self)
        self.result = f"(-{self.result})"


class EvalVisitor(Visitor):
    def __init__(self) -> None:
        self.result = 0.0

    def visit_number(self, node: NumberNode) -> None:
        self.result = node.value

    def visit_add(self, node: AddNode) -> None:
        node.left.accept(self)
        left = self.result
        node.right.accept(self)
        self.result = left + self.result

    def visit_multiply(self, node: MultiplyNode) -> None:
        node.left.accept(self)
        left = self.result
        node.right.accept(self)
        self.result = left * self.result

    def visit_negate(self, node: NegateNode) -> None:
        node.operand.accept(self)
        self.result = -self.result


def print_ast(node: Node) -> str:
    v = PrintVisitor()
    node.accept(v)
    return v.result


def eval_ast(node: Node) -> float:
    v = EvalVisitor()
    node.accept(v)
    return v.result


def main() -> None:
    # Build AST: (3 + 5) * -(2)
    tree = MultiplyNode(
        AddNode(NumberNode(3), NumberNode(5)),
        NegateNode(NumberNode(2)),
    )

    print(f"Expression: {print_ast(tree)}")
    print(f"Result:     {eval_ast(tree)}")

    # Another: 10 + (4 * 3)
    tree2 = AddNode(
        NumberNode(10),
        MultiplyNode(NumberNode(4), NumberNode(3)),
    )

    print(f"\nExpression: {print_ast(tree2)}")
    print(f"Result:     {eval_ast(tree2)}")

    # Simple: 42
    tree3 = NumberNode(42)
    print(f"\nExpression: {print_ast(tree3)}")
    print(f"Result:     {eval_ast(tree3)}")


if __name__ == "__main__":
    main()
```

**Output:**
```
Expression: ((3 + 5) * (-2))
Result:     -16.0

Expression: (10 + (4 * 3))
Result:     22.0

Expression: 42
Result:     42.0
```

## Go

```go
package main

import "fmt"

type Visitor interface {
	VisitNumber(n *NumberNode)
	VisitAdd(n *AddNode)
	VisitMultiply(n *MultiplyNode)
	VisitNegate(n *NegateNode)
}

type Node interface {
	Accept(v Visitor)
}

type NumberNode struct{ Value float64 }

func (n *NumberNode) Accept(v Visitor) { v.VisitNumber(n) }

type AddNode struct{ Left, Right Node }

func (n *AddNode) Accept(v Visitor) { v.VisitAdd(n) }

type MultiplyNode struct{ Left, Right Node }

func (n *MultiplyNode) Accept(v Visitor) { v.VisitMultiply(n) }

type NegateNode struct{ Operand Node }

func (n *NegateNode) Accept(v Visitor) { v.VisitNegate(n) }

// --- PrintVisitor ---
type PrintVisitor struct{ Result string }

func (pv *PrintVisitor) VisitNumber(n *NumberNode) {
	pv.Result = fmt.Sprintf("%g", n.Value)
}
func (pv *PrintVisitor) VisitAdd(n *AddNode) {
	n.Left.Accept(pv)
	left := pv.Result
	n.Right.Accept(pv)
	pv.Result = fmt.Sprintf("(%s + %s)", left, pv.Result)
}
func (pv *PrintVisitor) VisitMultiply(n *MultiplyNode) {
	n.Left.Accept(pv)
	left := pv.Result
	n.Right.Accept(pv)
	pv.Result = fmt.Sprintf("(%s * %s)", left, pv.Result)
}
func (pv *PrintVisitor) VisitNegate(n *NegateNode) {
	n.Operand.Accept(pv)
	pv.Result = fmt.Sprintf("(-%s)", pv.Result)
}

// --- EvalVisitor ---
type EvalVisitor struct{ Result float64 }

func (ev *EvalVisitor) VisitNumber(n *NumberNode) {
	ev.Result = n.Value
}
func (ev *EvalVisitor) VisitAdd(n *AddNode) {
	n.Left.Accept(ev)
	left := ev.Result
	n.Right.Accept(ev)
	ev.Result = left + ev.Result
}
func (ev *EvalVisitor) VisitMultiply(n *MultiplyNode) {
	n.Left.Accept(ev)
	left := ev.Result
	n.Right.Accept(ev)
	ev.Result = left * ev.Result
}
func (ev *EvalVisitor) VisitNegate(n *NegateNode) {
	n.Operand.Accept(ev)
	ev.Result = -ev.Result
}

func printAST(n Node) string {
	v := &PrintVisitor{}
	n.Accept(v)
	return v.Result
}

func evalAST(n Node) float64 {
	v := &EvalVisitor{}
	n.Accept(v)
	return v.Result
}

func main() {
	// (3 + 5) * -(2)
	tree := &MultiplyNode{
		Left:  &AddNode{Left: &NumberNode{3}, Right: &NumberNode{5}},
		Right: &NegateNode{Operand: &NumberNode{2}},
	}

	fmt.Printf("Expression: %s\n", printAST(tree))
	fmt.Printf("Result:     %g\n", evalAST(tree))

	// 10 + (4 * 3)
	tree2 := &AddNode{
		Left:  &NumberNode{10},
		Right: &MultiplyNode{Left: &NumberNode{4}, Right: &NumberNode{3}},
	}

	fmt.Printf("\nExpression: %s\n", printAST(tree2))
	fmt.Printf("Result:     %g\n", evalAST(tree2))

	// 42
	tree3 := &NumberNode{42}
	fmt.Printf("\nExpression: %s\n", printAST(tree3))
	fmt.Printf("Result:     %g\n", evalAST(tree3))
}
```

**Output:**
```
Expression: ((3 + 5) * (-2))
Result:     -16

Expression: (10 + (4 * 3))
Result:     22

Expression: 42
Result:     42
```

## JavaScript

```javascript
class NumberNode {
  constructor(value) {
    this.value = value;
  }
  accept(visitor) {
    visitor.visitNumber(this);
  }
}

class AddNode {
  constructor(left, right) {
    this.left = left;
    this.right = right;
  }
  accept(visitor) {
    visitor.visitAdd(this);
  }
}

class MultiplyNode {
  constructor(left, right) {
    this.left = left;
    this.right = right;
  }
  accept(visitor) {
    visitor.visitMultiply(this);
  }
}

class NegateNode {
  constructor(operand) {
    this.operand = operand;
  }
  accept(visitor) {
    visitor.visitNegate(this);
  }
}

class PrintVisitor {
  constructor() {
    this.result = "";
  }

  visitNumber(node) {
    this.result = `${node.value}`;
  }

  visitAdd(node) {
    node.left.accept(this);
    const left = this.result;
    node.right.accept(this);
    this.result = `(${left} + ${this.result})`;
  }

  visitMultiply(node) {
    node.left.accept(this);
    const left = this.result;
    node.right.accept(this);
    this.result = `(${left} * ${this.result})`;
  }

  visitNegate(node) {
    node.operand.accept(this);
    this.result = `(-${this.result})`;
  }
}

class EvalVisitor {
  constructor() {
    this.result = 0;
  }

  visitNumber(node) {
    this.result = node.value;
  }

  visitAdd(node) {
    node.left.accept(this);
    const left = this.result;
    node.right.accept(this);
    this.result = left + this.result;
  }

  visitMultiply(node) {
    node.left.accept(this);
    const left = this.result;
    node.right.accept(this);
    this.result = left * this.result;
  }

  visitNegate(node) {
    node.operand.accept(this);
    this.result = -this.result;
  }
}

function printAST(node) {
  const v = new PrintVisitor();
  node.accept(v);
  return v.result;
}

function evalAST(node) {
  const v = new EvalVisitor();
  node.accept(v);
  return v.result;
}

// --- Demo ---

// (3 + 5) * -(2)
const tree = new MultiplyNode(
  new AddNode(new NumberNode(3), new NumberNode(5)),
  new NegateNode(new NumberNode(2))
);

console.log(`Expression: ${printAST(tree)}`);
console.log(`Result:     ${evalAST(tree)}`);

// 10 + (4 * 3)
const tree2 = new AddNode(
  new NumberNode(10),
  new MultiplyNode(new NumberNode(4), new NumberNode(3))
);

console.log(`\nExpression: ${printAST(tree2)}`);
console.log(`Result:     ${evalAST(tree2)}`);

// 42
const tree3 = new NumberNode(42);
console.log(`\nExpression: ${printAST(tree3)}`);
console.log(`Result:     ${evalAST(tree3)}`);
```

**Output:**
```
Expression: ((3 + 5) * (-2))
Result:     -16

Expression: (10 + (4 * 3))
Result:     22

Expression: 42
Result:     42
```

## Related Patterns

- **Composite** — visitor is frequently applied to composite trees; `accept()` delegates to children naturally.
- **Iterator** — combine iterator (to traverse) with visitor (to operate on each element) for clean separation.
- **Strategy** — strategy swaps algorithms at runtime on a single type; visitor applies an algorithm across a type hierarchy.
- **Interpreter** — interpreters are often implemented as visitors that walk an AST.
