// Always thread-safe sclass FixedVarContext > VarContext { S[] names; // always sorted, may be null O[] values; // same length as names, may also be null *() {} *(S[] *names) { this(null, names); } *(VarContext parent, S[] *names) { super(parent); if (names != null) values = new O[names.length]; } int indexOfVar(S name) { ret indexOfInSortedArray(names, name); } int indexOfVarMandatory(S name) { int idx = indexOfVar(name); if (idx < 0) fail("Variable not found: " + name + ", known: " + joinWithComma(names)); ret idx; } O get(int idx) { ret values[idx]; } O get(S name) { int idx = indexOfVar(name); if (idx >= 0) ret values[idx]; if (parent != null) ret parent.get(name); null; } void set(int idx, O value) { values[idx] = value; } void set(S name, O value) { int idx = indexOfVar(name); if (idx >= 0) values[idx] = value; else fail("Variable " + name + " not defined in context"); } AutoCloseable tempSet(S name, O value) { int idx = indexOfVar(name); if (idx >= 0) { O old = values[idx]; values[idx] = value; ret -> values[idx] = old; } else fail("Variable " + name + " not defined in context"); } void unset(S name) { set(name, null); } MapSO varMap() { new MapSO map; int n = l(names); for i to n: map.put(names[i], values[i]); ret map; } }