Polymorphic AST eval
Interface / virtual-method dispatch through nine AST node types under heavy traversal load.
Runtime · median per inner-loop window
Full statistics
| Runner | N | Compile | Runtime | P95 | Stddev | RSS | vs piko | Status |
|---|---|---|---|---|---|---|---|---|
| Native Gocompiled | 10 | 181 ms | 2.11 ms | 2.13 ms | 12.0 µs | 69 MiB | 0.04× | OK |
| Piko interpbytecode VM | 10 | 2.03 ms | 54.9 ms | 55.4 ms | 309 µs | 131 MiB | 1.00× | OK |
| CPython 3.13bytecode VM | 10 | 620 µs | 55.7 ms | 57.5 ms | 1.25 ms | n/a | 1.01× | OK |
| PyPy 7.3tracing JIT | 10 | 482 µs | 80.1 ms | 83.5 ms | 1.19 ms | n/a | 1.46× | OK |
| tengobytecode VM | 10 | 373 µs | 120 ms | 123 ms | 1.19 ms | 200 MiB | 2.18× | OK |
| scriggobytecode VM | 0 | n/a | n/a | n/a | n/a | n/a | n/a | unsupported |
| mvmbytecode VM | 10 | 687 µs | 246 ms | 275 ms | 20.0 ms | 67 MiB | 4.49× | OK |
| yaegiAST walker | 10 | 702 µs | 1.40 s | 1.53 s | 49.4 ms | 71 MiB | 25.5× | OK |
Workload & symmetry rules
Workload
Build an expression tree from a deterministic LCG that mixes nine node kinds (Add, Sub, Mul, Mod, Const, Var, IfPos, Min, Max), each as a distinct struct/class satisfying a single-method contract: Node.Eval(env) uint32. Walk the tree repeatedly and accumulate the fold.
Symmetry rules
- Real interface dispatch in Go (
Eval(env)method on aNodeinterface) and class-based duck typing in Python. - No tagged-union switch shortcut; every Eval call must go through dynamic dispatch.
Why this benchmark exists
A direct measurement of the interpreter's interface / virtual-method dispatch path. Bench 05 is similar but uses a tagged-int switch; this one forces real virtual dispatch.
Source code
piko / Go
piko_source.gonative Go
native_main.goCPython / PyPy
cpython.pytengo
script.tengo