Skip to content

env EnvMap

Eugene Lazutkin edited this page Jul 13, 2026 · 3 revisions

This class is an alternative implementation of an environment object based on Map stacks. It is a sibling of Env and conforms to the same EnvLike contract; either can be passed to unify() and they are interchangeable.

EnvMap is defined in env-map.js and can be accessed like that:

import {EnvMap} from 'deep6/env-map.js';

When to use

Both implementations satisfy the same contract, but they have different performance profiles depending on workload shape:

  • EnvMap (Map-stack) is the default and is used internally when unify() is called without an explicit environment. It is faster on workloads with many distinct variable names per frame — particularly the alias-binding hot path and accumulating-symbol scenarios. The internal Map-of-name→value lookup avoids the dict-mode-deopt pressure that the proto-chain version pays once enough symbol-named bindings accumulate.
  • Env (proto-chain) is the opt-in sibling. It is fast for small environments and shallow nesting.

For solver-style consumers (e.g., yopl) where the binding count is large, EnvMap measures 4–8× faster on synthetic aggregate benchmarks. For occasional equal() / match() calls with small inputs, the difference between the implementations is negligible.

Explicit construction

unify() accepts any EnvLike instance as its third argument:

import {unify, variable} from 'deep6/unify.js';
import {EnvMap} from 'deep6/env-map.js';

const x = variable('x'),
  y = variable('y'),
  env = new EnvMap();

const result = unify({a: x, b: y}, {a: 1, b: 2}, env);
result === env; // true
x.get(env); // 1
y.get(env); // 2

Variable and Unifier instances are environment-agnostic — they work identically against either implementation through the EnvLike method API.

Class: EnvMap

This class defines objects with the following public properties:

  • depth — an integer value of the depth, the current generation number. The initial value is 0.
  • options — a plain object holding the behavioural flags read by unify(). Initially empty.

The class defines exactly the methods specified by EnvLike: push(), pop(), revert(depth), bindVar(name1, name2), bindVal(name, value), isBound(name), isAlias(name1, name2), get(name), getAllValues(). Their behavioural semantics match Env — only the underlying storage differs.

Implementation notes

Internally EnvMap keeps two parallel stacks indexed by depth:

  • valuesStack: Map[] — per-frame Map from variable name to bound value.
  • variablesStack: Map[] — per-frame Map from variable name to the alias Set it belongs to.

Frames are lazily allocated — pushing a generation does not allocate a Map until the first write at that depth. Lookups (get(), isBound(), isAlias()) walk the stack top→bottom and stop at the first hit, giving the expected shadowing semantics.

bindVar() merges alias Sets by union; bindVal() propagates a binding to every member of the alias Set in the top frame.

See also

  • EnvLike — the method contract implemented by both classes.
  • Env — the proto-chain sibling implementation.
  • unify() — accepts either implementation as its third argument.

Clone this wiki locally