about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--001help.cc16
-rw-r--r--010vm.cc40
-rw-r--r--011load.cc14
-rw-r--r--013update_operation.cc10
-rw-r--r--014literal_string.cc2
-rw-r--r--020run.cc18
-rw-r--r--021check_instruction.cc24
-rw-r--r--022arithmetic.cc46
-rw-r--r--023boolean.cc14
-rw-r--r--024jump.cc24
-rw-r--r--025compare.cc28
-rw-r--r--029tools.cc40
-rw-r--r--030container.cc110
-rw-r--r--031address.cc16
-rw-r--r--032array.cc52
-rw-r--r--033exclusive_container.cc32
-rw-r--r--034call.cc8
-rw-r--r--035call_ingredient.cc12
-rw-r--r--036call_reply.cc10
-rw-r--r--037recipe.cc12
-rw-r--r--038scheduler.cc38
-rw-r--r--039wait.cc16
-rw-r--r--040brace.cc32
-rw-r--r--041jump_target.cc18
-rw-r--r--042name.cc42
-rw-r--r--043new.cc58
-rw-r--r--044space.cc18
-rw-r--r--045space_surround.cc2
-rw-r--r--046closure_name.cc24
-rw-r--r--047global.cc6
-rw-r--r--048check_type_by_name.cc8
-rw-r--r--050scenario.cc34
-rw-r--r--052tangle.cc8
-rw-r--r--054dilated_reagent.cc4
-rw-r--r--056recipe_header.cc20
-rw-r--r--057static_dispatch.cc36
-rw-r--r--058generic_container.cc18
-rw-r--r--059generic_recipe.cc26
-rw-r--r--064random.cc10
-rw-r--r--070display.cc58
-rw-r--r--072scenario_screen.cc60
-rw-r--r--075scenario_console.cc52
-rw-r--r--080trace_browser.cc2
-rw-r--r--081run_interactive.cc36
-rw-r--r--082persist.cc14
45 files changed, 593 insertions, 575 deletions
diff --git a/001help.cc b/001help.cc
index da3b2b75..3ed85e12 100644
--- a/001help.cc
+++ b/001help.cc
@@ -87,6 +87,22 @@ bool is_equal(char* s, const char* lit) {
 //:
 //: 5. Integer overflow is still impossible to guard against. Maybe after
 //: reading http://www.cs.utah.edu/~regehr/papers/overflow12.pdf
+//:
+//: 6. Map's operator[] being non-const is fucking evil.
+:(before "Globals")  // can't generate prototypes for these
+// from http://stackoverflow.com/questions/152643/idiomatic-c-for-reading-from-a-const-map
+template<typename T> typename T::mapped_type& get(T& map, typename T::key_type const& key) {
+  typename T::iterator iter(map.find(key));
+  assert(iter != map.end());
+  return iter->second;
+}
+template<typename T> typename T::mapped_type& get_or_insert(T& map, typename T::key_type const& key) {
+  return map[key];
+}
+template<typename T> typename T::mapped_type const& put(T& map, typename T::key_type const& key, typename T::mapped_type const& value) {
+  map[key] = value;
+  return map[key];
+}
 
 :(before "End Includes")
 #include<assert.h>
diff --git a/010vm.cc b/010vm.cc
index 17f2140c..ef21cedf 100644
--- a/010vm.cc
+++ b/010vm.cc
@@ -34,7 +34,7 @@ struct instruction {
   string label;  // only if is_label
   string name;  // only if !is_label
   string old_name;  // before our automatic rewrite rules
-  recipe_ordinal operation;  // Recipe_ordinal[name]
+  recipe_ordinal operation;  // get(Recipe_ordinal, name)
   vector<reagent> ingredients;  // only if !is_label
   vector<reagent> products;  // only if !is_label
   // End instruction Fields
@@ -123,22 +123,22 @@ type_ordinal Next_type_ordinal = 1;
 :(code)
 void setup_types() {
   Type.clear();  Type_ordinal.clear();
-  Type_ordinal["literal"] = 0;
+  put(Type_ordinal, "literal", 0);
   Next_type_ordinal = 1;
   // Mu Types Initialization
-  type_ordinal number = Type_ordinal["number"] = Next_type_ordinal++;
-  Type_ordinal["location"] = Type_ordinal["number"];  // wildcard type: either a pointer or a scalar
-  Type[number].name = "number";
-  type_ordinal address = Type_ordinal["address"] = Next_type_ordinal++;
-  Type[address].name = "address";
-  type_ordinal boolean = Type_ordinal["boolean"] = Next_type_ordinal++;
-  Type[boolean].name = "boolean";
-  type_ordinal character = Type_ordinal["character"] = Next_type_ordinal++;
-  Type[character].name = "character";
+  type_ordinal number = put(Type_ordinal, "number", Next_type_ordinal++);
+  put(Type_ordinal, "location", get(Type_ordinal, "number"));  // wildcard type: either a pointer or a scalar
+  get(Type, number).name = "number";
+  type_ordinal address = put(Type_ordinal, "address", Next_type_ordinal++);
+  get(Type, address).name = "address";
+  type_ordinal boolean = put(Type_ordinal, "boolean", Next_type_ordinal++);
+  get(Type, boolean).name = "boolean";
+  type_ordinal character = put(Type_ordinal, "character", Next_type_ordinal++);
+  get(Type, character).name = "character";
   // Array types are a special modifier to any other type. For example,
   // array:number or array:address:boolean.
-  type_ordinal array = Type_ordinal["array"] = Next_type_ordinal++;
-  Type[array].name = "array";
+  type_ordinal array = put(Type_ordinal, "array", Next_type_ordinal++);
+  get(Type, array).name = "array";
   // End Mu Types Initialization
 }
 void teardown_types() {
@@ -196,9 +196,9 @@ enum primitive_recipes {
 //: what to do for them.
 void setup_recipes() {
   Recipe.clear();  Recipe_ordinal.clear();
-  Recipe_ordinal["idle"] = IDLE;
+  put(Recipe_ordinal, "idle", IDLE);
   // Primitive Recipe Numbers
-  Recipe_ordinal["copy"] = COPY;
+  put(Recipe_ordinal, "copy", COPY);
   // End Primitive Recipe Numbers
 }
 //: We could just reset the recipe table after every test, but that gets slow
@@ -209,7 +209,7 @@ void setup_recipes() {
 setup_recipes();
 assert(MAX_PRIMITIVE_RECIPES < 200);  // level 0 is primitives; until 199
 Next_recipe_ordinal = 200;
-Recipe_ordinal["main"] = Next_recipe_ordinal++;
+put(Recipe_ordinal, "main", Next_recipe_ordinal++);
 // End Load Recipes
 :(before "End Test Run Initialization")
 assert(Next_recipe_ordinal < 1000);  // recipes being tested didn't overflow into test space
@@ -276,9 +276,9 @@ type_tree* new_type_tree(const string_tree* properties) {
     if (Type_ordinal.find(type_name) == Type_ordinal.end()
         // types can contain integers, like for array sizes
         && !is_integer(type_name)) {
-      Type_ordinal[type_name] = Next_type_ordinal++;
+      put(Type_ordinal, type_name, Next_type_ordinal++);
     }
-    result->value = Type_ordinal[type_name];
+    result->value = get(Type_ordinal, type_name);
   }
   result->left = new_type_tree(properties->left);
   result->right = new_type_tree(properties->right);
@@ -414,7 +414,7 @@ void dump_types_tree(const type_tree* type, ostream& out) {
 
 void dump_type_name(recipe_ordinal type, ostream& out) {
   if (Type.find(type) != Type.end())
-    out << Type[type].name;
+    out << get(Type, type).name;
   else
     out << "?";
 }
@@ -470,7 +470,7 @@ void dump_memory() {
 }
 
 void dump_recipe(const string& recipe_name) {
-  const recipe& r = Recipe[Recipe_ordinal[recipe_name]];
+  const recipe& r = get(Recipe, get(Recipe_ordinal, recipe_name));
   cout << "recipe " << r.name << " [\n";
   for (long long int i = 0; i < SIZE(r.steps); ++i) {
     cout << "  " << r.steps.at(i).to_string() << '\n';
diff --git a/011load.cc b/011load.cc
index 10fe3817..d7150335 100644
--- a/011load.cc
+++ b/011load.cc
@@ -48,20 +48,20 @@ long long int slurp_recipe(istream& in) {
     raise_error << "empty result.name\n" << end();
   trace(9991, "parse") << "--- defining " << result.name << end();
   if (Recipe_ordinal.find(result.name) == Recipe_ordinal.end()) {
-    Recipe_ordinal[result.name] = Next_recipe_ordinal++;
+    put(Recipe_ordinal, result.name, Next_recipe_ordinal++);
   }
-  if (Recipe.find(Recipe_ordinal[result.name]) != Recipe.end()) {
+  if (Recipe.find(get(Recipe_ordinal, result.name)) != Recipe.end()) {
     trace(9991, "parse") << "already exists" << end();
     if (warn_on_redefine(result.name))
       raise << "redefining recipe " << result.name << "\n" << end();
-    Recipe.erase(Recipe_ordinal[result.name]);
+    Recipe.erase(get(Recipe_ordinal, result.name));
   }
   slurp_body(in, result);
   // End recipe Body(result)
-  Recipe[Recipe_ordinal[result.name]] = result;
+  get(Recipe, get(Recipe_ordinal, result.name)) = result;
   // track added recipes because we may need to undo them in tests; see below
-  recently_added_recipes.push_back(Recipe_ordinal[result.name]);
-  return Recipe_ordinal[result.name];
+  recently_added_recipes.push_back(get(Recipe_ordinal, result.name));
+  return get(Recipe_ordinal, result.name);
 }
 
 void slurp_body(istream& in, recipe& result) {
@@ -243,7 +243,7 @@ long long int Reserved_for_tests = 1000;
 :(before "End Setup")
 for (long long int i = 0; i < SIZE(recently_added_recipes); ++i) {
   if (recently_added_recipes.at(i) >= Reserved_for_tests)  // don't renumber existing recipes, like 'interactive'
-    Recipe_ordinal.erase(Recipe[recently_added_recipes.at(i)].name);
+    Recipe_ordinal.erase(get(Recipe, recently_added_recipes.at(i)).name);
   Recipe.erase(recently_added_recipes.at(i));
 }
 // Clear Other State For recently_added_recipes
diff --git a/013update_operation.cc b/013update_operation.cc
index 8ff8d628..13c7a3ad 100644
--- a/013update_operation.cc
+++ b/013update_operation.cc
@@ -6,15 +6,15 @@ Transform.push_back(update_instruction_operations);
 
 :(code)
 void update_instruction_operations(recipe_ordinal r) {
-  trace(9991, "transform") << "--- compute instruction operations for recipe " << Recipe[r].name << end();
-  for (long long int index = 0; index < SIZE(Recipe[r].steps); ++index) {
-    instruction& inst = Recipe[r].steps.at(index);
+  trace(9991, "transform") << "--- compute instruction operations for recipe " << get(Recipe, r).name << end();
+  for (long long int index = 0; index < SIZE(get(Recipe, r).steps); ++index) {
+    instruction& inst = get(Recipe, r).steps.at(index);
     if (inst.is_label) continue;
     if (Recipe_ordinal.find(inst.name) == Recipe_ordinal.end()) {
-      raise_error << maybe(Recipe[r].name) << "instruction " << inst.name << " has no recipe\n" << end();
+      raise_error << maybe(get(Recipe, r).name) << "instruction " << inst.name << " has no recipe\n" << end();
       return;
     }
-    inst.operation = Recipe_ordinal[inst.name];
+    inst.operation = get(Recipe_ordinal, inst.name);
   }
 }
 
diff --git a/014literal_string.cc b/014literal_string.cc
index 99e7c097..ce545547 100644
--- a/014literal_string.cc
+++ b/014literal_string.cc
@@ -19,7 +19,7 @@ recipe main [
 +parse:   ingredient: {"abc:def/ghi": "literal-string"}
 
 :(before "End Mu Types Initialization")
-Type_ordinal["literal-string"] = 0;
+put(Type_ordinal, "literal-string", 0);
 
 :(before "End next_word Special-cases")
   if (in.peek() == '[') {
diff --git a/020run.cc b/020run.cc
index 24a0a863..42b11fc2 100644
--- a/020run.cc
+++ b/020run.cc
@@ -63,9 +63,9 @@ void run_current_routine()
 //?     Instructions_running[current_recipe_name()]++;
     if (current_instruction().is_label) { ++current_step_index(); continue; }
     trace(Initial_callstack_depth + Trace_stream->callstack_depth, "run") << current_instruction().to_string() << end();
-    if (Memory[0] != 0) {
+    if (get_or_insert(Memory, 0) != 0) {
       raise_error << "something wrote to location 0; this should never happen\n" << end();
-      Memory[0] = 0;
+      put(Memory, 0, 0);
     }
     // Read all ingredients from memory.
     // Each ingredient loads a vector of values rather than a single value; mu
@@ -119,15 +119,15 @@ inline long long int& current_step_index() {
 }
 
 inline const string& current_recipe_name() {
-  return Recipe[Current_routine->running_recipe].name;
+  return get(Recipe, Current_routine->running_recipe).name;
 }
 
 inline const instruction& current_instruction() {
-  return Recipe[Current_routine->running_recipe].steps.at(Current_routine->running_step_index);
+  return get(Recipe, Current_routine->running_recipe).steps.at(Current_routine->running_step_index);
 }
 
 inline bool routine::completed() const {
-  return running_step_index >= SIZE(Recipe[running_recipe].steps);
+  return running_step_index >= SIZE(get(Recipe, running_recipe).steps);
 }
 
 //:: Startup flow
@@ -154,7 +154,7 @@ if (argc > 1) {
   }
   transform_all();
 //?   dump_recipe("handle-keyboard-event"),  exit(0);
-  if (Run_tests) Recipe.erase(Recipe_ordinal[string("main")]);
+  if (Run_tests) Recipe.erase(get(Recipe_ordinal, string("main")));
 }
 
 //: Step 3: if we aren't running tests, locate a recipe called 'main' and
@@ -171,7 +171,7 @@ if (!Run_tests) {
 
 :(code)
 void run_main(int argc, char* argv[]) {
-  recipe_ordinal r = Recipe_ordinal[string("main")];
+  recipe_ordinal r = get(Recipe_ordinal, string("main"));
   if (r) run(r);
 }
 
@@ -258,7 +258,7 @@ vector<double> read_memory(reagent x) {
   long long int base = x.value;
   long long int size = size_of(x);
   for (long long int offset = 0; offset < size; ++offset) {
-    double val = Memory[base+offset];
+    double val = get_or_insert(Memory, base+offset);
     trace(9999, "mem") << "location " << base+offset << " is " << no_scientific(val) << end();
     result.push_back(val);
   }
@@ -276,7 +276,7 @@ void write_memory(reagent x, vector<double> data) {
   for (long long int offset = 0; offset < SIZE(data); ++offset) {
     if (base+offset == 0) continue;
     trace(9999, "mem") << "storing " << no_scientific(data.at(offset)) << " in location " << base+offset << end();
-    Memory[base+offset] = data.at(offset);
+    put(Memory, base+offset, data.at(offset));
   }
 }
 
diff --git a/021check_instruction.cc b/021check_instruction.cc
index d0efd2a2..3c44f36a 100644
--- a/021check_instruction.cc
+++ b/021check_instruction.cc
@@ -13,10 +13,10 @@ Transform.push_back(check_instruction);
 
 :(code)
 void check_instruction(const recipe_ordinal r) {
-  trace(9991, "transform") << "--- perform checks for recipe " << Recipe[r].name << end();
+  trace(9991, "transform") << "--- perform checks for recipe " << get(Recipe, r).name << end();
   map<string, vector<type_ordinal> > metadata;
-  for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
-    instruction& inst = Recipe[r].steps.at(i);
+  for (long long int i = 0; i < SIZE(get(Recipe, r).steps); ++i) {
+    instruction& inst = get(Recipe, r).steps.at(i);
     if (inst.is_label) continue;
     switch (inst.operation) {
       // Primitive Recipe Checks
@@ -27,7 +27,7 @@ void check_instruction(const recipe_ordinal r) {
         }
         for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
           if (!types_match(inst.products.at(i), inst.ingredients.at(i))) {
-            raise_error << maybe(Recipe[r].name) << "can't copy " << inst.ingredients.at(i).original_string << " to " << inst.products.at(i).original_string << "; types don't match\n" << end();
+            raise_error << maybe(get(Recipe, r).name) << "can't copy " << inst.ingredients.at(i).original_string << " to " << inst.products.at(i).original_string << "; types don't match\n" << end();
             goto finish_checking_instruction;
           }
         }
@@ -90,8 +90,8 @@ bool types_match(reagent lhs, reagent rhs) {
 bool types_match(type_tree* lhs, type_tree* rhs) {
   if (!lhs) return true;
   if (!rhs || rhs->value == 0) {
-    if (lhs->value == Type_ordinal["array"]) return false;
-    if (lhs->value == Type_ordinal["address"]) return false;
+    if (lhs->value == get(Type_ordinal, "array")) return false;
+    if (lhs->value == get(Type_ordinal, "address")) return false;
     return size_of(rhs) == size_of(lhs);
   }
   if (lhs->value != rhs->value) return false;
@@ -102,8 +102,8 @@ bool types_match(type_tree* lhs, type_tree* rhs) {
 bool types_match(const reagent lhs, const type_tree* rhs, const vector<double>& data) {
   if (is_dummy(lhs)) return true;
   if (rhs->value == 0) {
-    if (lhs.type->value == Type_ordinal["array"]) return false;
-    if (lhs.type->value == Type_ordinal["address"]) return scalar(data) && data.at(0) == 0;
+    if (lhs.type->value == get(Type_ordinal, "array")) return false;
+    if (lhs.type->value == get(Type_ordinal, "address")) return scalar(data) && data.at(0) == 0;
     return size_of(rhs) == size_of(lhs);
   }
   if (lhs.type->value != rhs->value) return false;
@@ -117,13 +117,13 @@ bool is_raw(const reagent& r) {
 bool is_mu_array(reagent r) {
   if (!r.type) return false;
   if (is_literal(r)) return false;
-  return r.type->value == Type_ordinal["array"];
+  return r.type->value == get(Type_ordinal, "array");
 }
 
 bool is_mu_address(reagent r) {
   if (!r.type) return false;
   if (is_literal(r)) return false;
-  return r.type->value == Type_ordinal["address"];
+  return r.type->value == get(Type_ordinal, "address");
 }
 
 bool is_mu_number(reagent r) {
@@ -131,8 +131,8 @@ bool is_mu_number(reagent r) {
   if (is_literal(r))
     return r.properties.at(0).second->value == "literal-number"
         || r.properties.at(0).second->value == "literal";
-  if (r.type->value == Type_ordinal["character"]) return true;  // permit arithmetic on unicode code points
-  return r.type->value == Type_ordinal["number"];
+  if (r.type->value == get(Type_ordinal, "character")) return true;  // permit arithmetic on unicode code points
+  return r.type->value == get(Type_ordinal, "number");
 }
 
 bool is_mu_scalar(reagent r) {
diff --git a/022arithmetic.cc b/022arithmetic.cc
index 817cd5f2..b16bc584 100644
--- a/022arithmetic.cc
+++ b/022arithmetic.cc
@@ -3,22 +3,22 @@
 :(before "End Primitive Recipe Declarations")
 ADD,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["add"] = ADD;
+put(Recipe_ordinal, "add", ADD);
 :(before "End Primitive Recipe Checks")
 case ADD: {
   // primary goal of these checks is to forbid address arithmetic
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise_error << maybe(Recipe[r].name) << "'add' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise_error << maybe(get(Recipe, r).name) << "'add' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise_error << maybe(Recipe[r].name) << "'add' yields exactly one product in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'add' yields exactly one product in '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "'add' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'add' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -71,26 +71,26 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 SUBTRACT,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["subtract"] = SUBTRACT;
+put(Recipe_ordinal, "subtract", SUBTRACT);
 :(before "End Primitive Recipe Checks")
 case SUBTRACT: {
   if (inst.ingredients.empty()) {
-    raise_error << maybe(Recipe[r].name) << "'subtract' has no ingredients\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'subtract' has no ingredients\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (is_raw(inst.ingredients.at(i))) continue;  // permit address offset computations in tests
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise_error << maybe(Recipe[r].name) << "'subtract' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise_error << maybe(get(Recipe, r).name) << "'subtract' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise_error << maybe(Recipe[r].name) << "'subtract' yields exactly one product in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'subtract' yields exactly one product in '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "'subtract' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'subtract' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -128,21 +128,21 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 MULTIPLY,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["multiply"] = MULTIPLY;
+put(Recipe_ordinal, "multiply", MULTIPLY);
 :(before "End Primitive Recipe Checks")
 case MULTIPLY: {
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise_error << maybe(Recipe[r].name) << "'multiply' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise_error << maybe(get(Recipe, r).name) << "'multiply' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise_error << maybe(Recipe[r].name) << "'multiply' yields exactly one product in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'multiply' yields exactly one product in '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "'multiply' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'multiply' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -181,25 +181,25 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 DIVIDE,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["divide"] = DIVIDE;
+put(Recipe_ordinal, "divide", DIVIDE);
 :(before "End Primitive Recipe Checks")
 case DIVIDE: {
   if (inst.ingredients.empty()) {
-    raise_error << maybe(Recipe[r].name) << "'divide' has no ingredients\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'divide' has no ingredients\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise_error << maybe(Recipe[r].name) << "'divide' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise_error << maybe(get(Recipe, r).name) << "'divide' requires number ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
   if (SIZE(inst.products) > 1) {
-    raise_error << maybe(Recipe[r].name) << "'divide' yields exactly one product in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'divide' yields exactly one product in '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!inst.products.empty() && !is_dummy(inst.products.at(0)) && !is_mu_number(inst.products.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "'divide' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'divide' should yield a number, but got " << inst.products.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -239,24 +239,24 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 DIVIDE_WITH_REMAINDER,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["divide-with-remainder"] = DIVIDE_WITH_REMAINDER;
+put(Recipe_ordinal, "divide-with-remainder", DIVIDE_WITH_REMAINDER);
 :(before "End Primitive Recipe Checks")
 case DIVIDE_WITH_REMAINDER: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(Recipe[r].name) << "'divide-with-remainder' requires exactly two ingredients, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'divide-with-remainder' requires exactly two ingredients, but got '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0)) || !is_mu_number(inst.ingredients.at(1))) {
-    raise_error << maybe(Recipe[r].name) << "'divide-with-remainder' requires number ingredients, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'divide-with-remainder' requires number ingredients, but got '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (SIZE(inst.products) > 2) {
-    raise_error << maybe(Recipe[r].name) << "'divide-with-remainder' yields two products in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'divide-with-remainder' yields two products in '" << inst.to_string() << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.products); ++i) {
     if (!is_dummy(inst.products.at(i)) && !is_mu_number(inst.products.at(i))) {
-      raise_error << maybe(Recipe[r].name) << "'divide-with-remainder' should yield a number, but got " << inst.products.at(i).original_string << '\n' << end();
+      raise_error << maybe(get(Recipe, r).name) << "'divide-with-remainder' should yield a number, but got " << inst.products.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
diff --git a/023boolean.cc b/023boolean.cc
index 49683455..13400c4c 100644
--- a/023boolean.cc
+++ b/023boolean.cc
@@ -3,12 +3,12 @@
 :(before "End Primitive Recipe Declarations")
 AND,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["and"] = AND;
+put(Recipe_ordinal, "and", AND);
 :(before "End Primitive Recipe Checks")
 case AND: {
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_scalar(inst.ingredients.at(i))) {
-      raise_error << maybe(Recipe[r].name) << "'and' requires boolean ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise_error << maybe(get(Recipe, r).name) << "'and' requires boolean ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
@@ -53,12 +53,12 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 OR,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["or"] = OR;
+put(Recipe_ordinal, "or", OR);
 :(before "End Primitive Recipe Checks")
 case OR: {
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_scalar(inst.ingredients.at(i))) {
-      raise_error << maybe(Recipe[r].name) << "'and' requires boolean ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise_error << maybe(get(Recipe, r).name) << "'and' requires boolean ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
@@ -103,16 +103,16 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 NOT,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["not"] = NOT;
+put(Recipe_ordinal, "not", NOT);
 :(before "End Primitive Recipe Checks")
 case NOT: {
   if (SIZE(inst.products) > SIZE(inst.ingredients)) {
-    raise_error << maybe(Recipe[r].name) << "'not' cannot have fewer ingredients than products in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'not' cannot have fewer ingredients than products in '" << inst.to_string() << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_scalar(inst.ingredients.at(i))) {
-      raise_error << maybe(Recipe[r].name) << "'not' requires boolean ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise_error << maybe(get(Recipe, r).name) << "'not' requires boolean ingredients, but got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
diff --git a/024jump.cc b/024jump.cc
index 30d5381f..95e31c55 100644
--- a/024jump.cc
+++ b/024jump.cc
@@ -12,15 +12,15 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 JUMP,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["jump"] = JUMP;
+put(Recipe_ordinal, "jump", JUMP);
 :(before "End Primitive Recipe Checks")
 case JUMP: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(Recipe[r].name) << "'jump' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'jump' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "first ingredient of 'jump' should be a label or offset, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'jump' should be a label or offset, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -35,7 +35,7 @@ case JUMP: {
 
 //: special type to designate jump targets
 :(before "End Mu Types Initialization")
-Type_ordinal["offset"] = 0;
+put(Type_ordinal, "offset", 0);
 
 :(scenario jump_backward)
 recipe main [
@@ -51,19 +51,19 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 JUMP_IF,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["jump-if"] = JUMP_IF;
+put(Recipe_ordinal, "jump-if", JUMP_IF);
 :(before "End Primitive Recipe Checks")
 case JUMP_IF: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(Recipe[r].name) << "'jump-if' requires exactly two ingredients, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'jump-if' requires exactly two ingredients, but got " << inst.to_string() << '\n' << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "'jump-if' requires a boolean for its first ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'jump-if' requires a boolean for its first ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(1))) {
-    raise_error << maybe(Recipe[r].name) << "'jump-if' requires a label or offset for its second ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'jump-if' requires a label or offset for its second ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -103,19 +103,19 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 JUMP_UNLESS,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["jump-unless"] = JUMP_UNLESS;
+put(Recipe_ordinal, "jump-unless", JUMP_UNLESS);
 :(before "End Primitive Recipe Checks")
 case JUMP_UNLESS: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(Recipe[r].name) << "'jump-unless' requires exactly two ingredients, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'jump-unless' requires exactly two ingredients, but got " << inst.to_string() << '\n' << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "'jump-unless' requires a boolean for its first ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'jump-unless' requires a boolean for its first ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(1))) {
-    raise_error << maybe(Recipe[r].name) << "'jump-unless' requires a label or offset for its second ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'jump-unless' requires a label or offset for its second ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   break;
diff --git a/025compare.cc b/025compare.cc
index f7acb64c..056c859d 100644
--- a/025compare.cc
+++ b/025compare.cc
@@ -3,11 +3,11 @@
 :(before "End Primitive Recipe Declarations")
 EQUAL,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["equal"] = EQUAL;
+put(Recipe_ordinal, "equal", EQUAL);
 :(before "End Primitive Recipe Checks")
 case EQUAL: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise_error << maybe(Recipe[r].name) << "'equal' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'equal' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
     break;
   }
   break;
@@ -62,16 +62,16 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 GREATER_THAN,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["greater-than"] = GREATER_THAN;
+put(Recipe_ordinal, "greater-than", GREATER_THAN);
 :(before "End Primitive Recipe Checks")
 case GREATER_THAN: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise_error << maybe(Recipe[r].name) << "'greater-than' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'greater-than' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise_error << maybe(Recipe[r].name) << "'greater-than' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise_error << maybe(get(Recipe, r).name) << "'greater-than' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
@@ -121,16 +121,16 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 LESSER_THAN,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["lesser-than"] = LESSER_THAN;
+put(Recipe_ordinal, "lesser-than", LESSER_THAN);
 :(before "End Primitive Recipe Checks")
 case LESSER_THAN: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise_error << maybe(Recipe[r].name) << "'lesser-than' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'lesser-than' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise_error << maybe(Recipe[r].name) << "'lesser-than' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise_error << maybe(get(Recipe, r).name) << "'lesser-than' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
@@ -180,16 +180,16 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 GREATER_OR_EQUAL,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["greater-or-equal"] = GREATER_OR_EQUAL;
+put(Recipe_ordinal, "greater-or-equal", GREATER_OR_EQUAL);
 :(before "End Primitive Recipe Checks")
 case GREATER_OR_EQUAL: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise_error << maybe(Recipe[r].name) << "'greater-or-equal' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'greater-or-equal' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise_error << maybe(Recipe[r].name) << "'greater-or-equal' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise_error << maybe(get(Recipe, r).name) << "'greater-or-equal' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
@@ -247,16 +247,16 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 LESSER_OR_EQUAL,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["lesser-or-equal"] = LESSER_OR_EQUAL;
+put(Recipe_ordinal, "lesser-or-equal", LESSER_OR_EQUAL);
 :(before "End Primitive Recipe Checks")
 case LESSER_OR_EQUAL: {
   if (SIZE(inst.ingredients) <= 1) {
-    raise_error << maybe(Recipe[r].name) << "'lesser-or-equal' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'lesser-or-equal' needs at least two ingredients to compare in '" << inst.to_string() << "'\n" << end();
     break;
   }
   for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
     if (!is_mu_number(inst.ingredients.at(i))) {
-      raise_error << maybe(Recipe[r].name) << "'lesser-or-equal' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
+      raise_error << maybe(get(Recipe, r).name) << "'lesser-or-equal' can only compare numbers; got " << inst.ingredients.at(i).original_string << '\n' << end();
       goto finish_checking_instruction;
     }
   }
diff --git a/029tools.cc b/029tools.cc
index 2aa06f62..92f551b3 100644
--- a/029tools.cc
+++ b/029tools.cc
@@ -9,19 +9,19 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 TRACE,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["trace"] = TRACE;
+put(Recipe_ordinal, "trace", TRACE);
 :(before "End Primitive Recipe Checks")
 case TRACE: {
   if (SIZE(inst.ingredients) < 3) {
-    raise_error << maybe(Recipe[r].name) << "'trace' takes three or more ingredients rather than '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'trace' takes three or more ingredients rather than '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "first ingredient of 'trace' should be a number (depth), but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'trace' should be a number (depth), but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   if (!is_literal_string(inst.ingredients.at(1))) {
-    raise_error << maybe(Recipe[r].name) << "second ingredient of 'trace' should be a literal string (label), but got " << inst.ingredients.at(1).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "second ingredient of 'trace' should be a literal string (label), but got " << inst.ingredients.at(1).original_string << '\n' << end();
     break;
   }
   break;
@@ -43,7 +43,7 @@ case TRACE: {
 :(before "End Primitive Recipe Declarations")
 STASH,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["stash"] = STASH;
+put(Recipe_ordinal, "stash", STASH);
 :(before "End Primitive Recipe Checks")
 case STASH: {
   break;
@@ -92,7 +92,7 @@ string print_mu(const reagent& r, const vector<double>& data) {
 :(before "End Primitive Recipe Declarations")
 HIDE_ERRORS,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["hide-errors"] = HIDE_ERRORS;
+put(Recipe_ordinal, "hide-errors", HIDE_ERRORS);
 :(before "End Primitive Recipe Checks")
 case HIDE_ERRORS: {
   break;
@@ -107,7 +107,7 @@ case HIDE_ERRORS: {
 :(before "End Primitive Recipe Declarations")
 SHOW_ERRORS,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["show-errors"] = SHOW_ERRORS;
+put(Recipe_ordinal, "show-errors", SHOW_ERRORS);
 :(before "End Primitive Recipe Checks")
 case SHOW_ERRORS: {
   break;
@@ -122,7 +122,7 @@ case SHOW_ERRORS: {
 :(before "End Primitive Recipe Declarations")
 TRACE_UNTIL,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["trace-until"] = TRACE_UNTIL;
+put(Recipe_ordinal, "trace-until", TRACE_UNTIL);
 :(before "End Primitive Recipe Checks")
 case TRACE_UNTIL: {
   break;
@@ -138,7 +138,7 @@ case TRACE_UNTIL: {
 :(before "End Primitive Recipe Declarations")
 _DUMP_TRACE,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$dump-trace"] = _DUMP_TRACE;
+put(Recipe_ordinal, "$dump-trace", _DUMP_TRACE);
 :(before "End Primitive Recipe Checks")
 case _DUMP_TRACE: {
   break;
@@ -157,7 +157,7 @@ case _DUMP_TRACE: {
 :(before "End Primitive Recipe Declarations")
 _CLEAR_TRACE,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$clear-trace"] = _CLEAR_TRACE;
+put(Recipe_ordinal, "$clear-trace", _CLEAR_TRACE);
 :(before "End Primitive Recipe Checks")
 case _CLEAR_TRACE: {
   break;
@@ -171,7 +171,7 @@ case _CLEAR_TRACE: {
 :(before "End Primitive Recipe Declarations")
 _SAVE_TRACE,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$save-trace"] = _SAVE_TRACE;
+put(Recipe_ordinal, "$save-trace", _SAVE_TRACE);
 :(before "End Primitive Recipe Checks")
 case _SAVE_TRACE: {
   break;
@@ -198,19 +198,19 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 ASSERT,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["assert"] = ASSERT;
+put(Recipe_ordinal, "assert", ASSERT);
 :(before "End Primitive Recipe Checks")
 case ASSERT: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(Recipe[r].name) << "'assert' takes exactly two ingredients rather than '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'assert' takes exactly two ingredients rather than '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!is_mu_scalar(inst.ingredients.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "'assert' requires a boolean for its first ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'assert' requires a boolean for its first ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   if (!is_literal_string(inst.ingredients.at(1))) {
-    raise_error << maybe(Recipe[r].name) << "'assert' requires a literal string for its second ingredient, but got " << inst.ingredients.at(1).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'assert' requires a literal string for its second ingredient, but got " << inst.ingredients.at(1).original_string << '\n' << end();
     break;
   }
   break;
@@ -228,7 +228,7 @@ case ASSERT: {
 :(before "End Primitive Recipe Declarations")
 _PRINT,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$print"] = _PRINT;
+put(Recipe_ordinal, "$print", _PRINT);
 :(before "End Primitive Recipe Checks")
 case _PRINT: {
   break;
@@ -257,7 +257,7 @@ case _PRINT: {
 :(before "End Primitive Recipe Declarations")
 _EXIT,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$exit"] = _EXIT;
+put(Recipe_ordinal, "$exit", _EXIT);
 :(before "End Primitive Recipe Checks")
 case _EXIT: {
   break;
@@ -271,11 +271,11 @@ case _EXIT: {
 :(before "End Primitive Recipe Declarations")
 _SYSTEM,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$system"] = _SYSTEM;
+put(Recipe_ordinal, "$system", _SYSTEM);
 :(before "End Primitive Recipe Checks")
 case _SYSTEM: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(Recipe[r].name) << "'$system' requires exactly one ingredient, but got none\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'$system' requires exactly one ingredient, but got none\n" << end();
     break;
   }
   break;
@@ -291,7 +291,7 @@ case _SYSTEM: {
 :(before "End Primitive Recipe Declarations")
 _DUMP_MEMORY,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$dump-memory"] = _DUMP_MEMORY;
+put(Recipe_ordinal, "$dump-memory", _DUMP_MEMORY);
 :(before "End Primitive Recipe Checks")
 case _DUMP_MEMORY: {
   break;
diff --git a/030container.cc b/030container.cc
index 9fde367e..05483cf4 100644
--- a/030container.cc
+++ b/030container.cc
@@ -2,14 +2,14 @@
 
 :(before "End Mu Types Initialization")
 //: We'll use this container as a running example, with two number elements.
-type_ordinal point = Type_ordinal["point"] = Next_type_ordinal++;
-Type[point].size = 2;
-Type[point].kind = CONTAINER;
-Type[point].name = "point";
-Type[point].elements.push_back(new type_tree(number));
-Type[point].element_names.push_back("x");
-Type[point].elements.push_back(new type_tree(number));
-Type[point].element_names.push_back("y");
+type_ordinal point = put(Type_ordinal, "point", Next_type_ordinal++);
+get(Type, point).size = 2;
+get(Type, point).kind = CONTAINER;
+get(Type, point).name = "point";
+get(Type, point).elements.push_back(new type_tree(number));
+get(Type, point).element_names.push_back("x");
+get(Type, point).elements.push_back(new type_tree(number));
+get(Type, point).element_names.push_back("y");
 
 //: Containers can be copied around with a single instruction just like
 //: numbers, no matter how large they are.
@@ -37,14 +37,14 @@ recipe main [
 :(before "End Mu Types Initialization")
 // A more complex container, containing another container as one of its
 // elements.
-type_ordinal point_number = Type_ordinal["point-number"] = Next_type_ordinal++;
-Type[point_number].size = 2;
-Type[point_number].kind = CONTAINER;
-Type[point_number].name = "point-number";
-Type[point_number].elements.push_back(new type_tree(point));
-Type[point_number].element_names.push_back("xy");
-Type[point_number].elements.push_back(new type_tree(number));
-Type[point_number].element_names.push_back("z");
+type_ordinal point_number = put(Type_ordinal, "point-number", Next_type_ordinal++);
+get(Type, point_number).size = 2;
+get(Type, point_number).kind = CONTAINER;
+get(Type, point_number).name = "point-number";
+get(Type, point_number).elements.push_back(new type_tree(point));
+get(Type, point_number).element_names.push_back("xy");
+get(Type, point_number).elements.push_back(new type_tree(number));
+get(Type, point_number).element_names.push_back("z");
 
 :(scenario copy_handles_nested_container_elements)
 recipe main [
@@ -87,7 +87,7 @@ if (type->value == 0) {
   assert(!type->left && !type->right);
   return 1;
 }
-type_info t = Type[type->value];
+type_info t = get(Type, type->value);
 if (t.kind == CONTAINER) {
   // size of a container is the sum of the sizes of its elements
   long long int result = 0;
@@ -124,23 +124,23 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 GET,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["get"] = GET;
+put(Recipe_ordinal, "get", GET);
 :(before "End Primitive Recipe Checks")
 case GET: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(Recipe[r].name) << "'get' expects exactly 2 ingredients in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'get' expects exactly 2 ingredients in '" << inst.to_string() << "'\n" << end();
     break;
   }
   reagent base = inst.ingredients.at(0);  // new copy for every invocation
   // Update GET base in Check
-  if (!base.type || !base.type->value || Type[base.type->value].kind != CONTAINER) {
-    raise_error << maybe(Recipe[r].name) << "first ingredient of 'get' should be a container, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+  if (!base.type || !base.type->value || get(Type, base.type->value).kind != CONTAINER) {
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'get' should be a container, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   type_ordinal base_type = base.type->value;
   reagent offset = inst.ingredients.at(1);
   if (!is_literal(offset) || !is_mu_scalar(offset)) {
-    raise_error << maybe(Recipe[r].name) << "second ingredient of 'get' should have type 'offset', but got " << inst.ingredients.at(1).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "second ingredient of 'get' should have type 'offset', but got " << inst.ingredients.at(1).original_string << '\n' << end();
     break;
   }
   long long int offset_value = 0;
@@ -148,15 +148,15 @@ case GET: {
     offset_value = to_integer(offset.name);
   else
     offset_value = offset.value;
-  if (offset_value < 0 || offset_value >= SIZE(Type[base_type].elements)) {
-    raise_error << maybe(Recipe[r].name) << "invalid offset " << offset_value << " for " << Type[base_type].name << '\n' << end();
+  if (offset_value < 0 || offset_value >= SIZE(get(Type, base_type).elements)) {
+    raise_error << maybe(get(Recipe, r).name) << "invalid offset " << offset_value << " for " << Type[base_type].name << '\n' << end();
     break;
   }
   reagent product = inst.products.at(0);
   // Update GET product in Check
   const reagent element = element_type(base, offset_value);
   if (!types_match(product, element)) {
-    raise_error << maybe(Recipe[r].name) << "'get' " << offset.original_string << " (" << offset_value << ") on " << Type[base_type].name << " can't be saved in " << product.original_string << "; type should be " << dump_types(element) << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'get' " << offset.original_string << " (" << offset_value << ") on " << Type[base_type].name << " can't be saved in " << product.original_string << "; type should be " << dump_types(element) << '\n' << end();
     break;
   }
   break;
@@ -172,11 +172,11 @@ case GET: {
   }
   type_ordinal base_type = base.type->value;
   long long int offset = ingredients.at(1).at(0);
-  if (offset < 0 || offset >= SIZE(Type[base_type].elements)) break;  // copied from Check above
+  if (offset < 0 || offset >= SIZE(get(Type, base_type).elements)) break;  // copied from Check above
   long long int src = base_address;
   for (long long int i = 0; i < offset; ++i) {
     // End GET field Cases
-    src += size_of(Type[base_type].elements.at(i));
+    src += size_of(get(Type, base_type).elements.at(i));
   }
   trace(9998, "run") << "address to copy is " << src << end();
   reagent tmp = element_type(base, offset);
@@ -190,8 +190,8 @@ case GET: {
 const reagent element_type(const reagent& canonized_base, long long int offset_value) {
   assert(offset_value >= 0);
   assert(Type.find(canonized_base.type->value) != Type.end());
-  assert(!Type[canonized_base.type->value].name.empty());
-  const type_info& info = Type[canonized_base.type->value];
+  assert(!get(Type, canonized_base.type->value).name.empty());
+  const type_info& info = get(Type, canonized_base.type->value);
   assert(info.kind == CONTAINER);
   reagent element;
   element.type = new type_tree(*info.elements.at(offset_value));
@@ -251,30 +251,30 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 GET_ADDRESS,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["get-address"] = GET_ADDRESS;
+put(Recipe_ordinal, "get-address", GET_ADDRESS);
 :(before "End Primitive Recipe Checks")
 case GET_ADDRESS: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(Recipe[r].name) << "'get-address' expects exactly 2 ingredients in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'get-address' expects exactly 2 ingredients in '" << inst.to_string() << "'\n" << end();
     break;
   }
   reagent base = inst.ingredients.at(0);
   // Update GET_ADDRESS base in Check
-  if (!base.type || Type[base.type->value].kind != CONTAINER) {
-    raise_error << maybe(Recipe[r].name) << "first ingredient of 'get-address' should be a container, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+  if (!base.type || get(Type, base.type->value).kind != CONTAINER) {
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'get-address' should be a container, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   type_ordinal base_type = base.type->value;
   reagent offset = inst.ingredients.at(1);
   if (!is_literal(offset) || !is_mu_scalar(offset)) {
-    raise_error << maybe(Recipe[r].name) << "second ingredient of 'get' should have type 'offset', but got " << inst.ingredients.at(1).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "second ingredient of 'get' should have type 'offset', but got " << inst.ingredients.at(1).original_string << '\n' << end();
     break;
   }
   long long int offset_value = 0;
   if (is_integer(offset.name)) {  // later layers permit non-integer offsets
     offset_value = to_integer(offset.name);
-    if (offset_value < 0 || offset_value >= SIZE(Type[base_type].elements)) {
-      raise_error << maybe(Recipe[r].name) << "invalid offset " << offset_value << " for " << Type[base_type].name << '\n' << end();
+    if (offset_value < 0 || offset_value >= SIZE(get(Type, base_type).elements)) {
+      raise_error << maybe(get(Recipe, r).name) << "invalid offset " << offset_value << " for " << Type[base_type].name << '\n' << end();
       break;
     }
   }
@@ -286,9 +286,9 @@ case GET_ADDRESS: {
   // same type as for GET..
   reagent element = element_type(base, offset_value);
   // ..except for an address at the start
-  element.type = new type_tree(Type_ordinal["address"], element.type);
+  element.type = new type_tree(get(Type_ordinal, "address"), element.type);
   if (!types_match(product, element)) {
-    raise_error << maybe(Recipe[r].name) << "'get-address' " << offset.original_string << " (" << offset_value << ") on " << Type[base_type].name << " can't be saved in " << product.original_string << "; type should be " << dump_types(element) << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'get-address' " << offset.original_string << " (" << offset_value << ") on " << Type[base_type].name << " can't be saved in " << product.original_string << "; type should be " << dump_types(element) << '\n' << end();
     break;
   }
   break;
@@ -304,11 +304,11 @@ case GET_ADDRESS: {
   }
   type_ordinal base_type = base.type->value;
   long long int offset = ingredients.at(1).at(0);
-  if (offset < 0 || offset >= SIZE(Type[base_type].elements)) break;  // copied from Check above
+  if (offset < 0 || offset >= SIZE(get(Type, base_type).elements)) break;  // copied from Check above
   long long int result = base_address;
   for (long long int i = 0; i < offset; ++i) {
     // End GET_ADDRESS field Cases
-    result += size_of(Type[base_type].elements.at(i));
+    result += size_of(get(Type, base_type).elements.at(i));
   }
   trace(9998, "run") << "address to copy is " << result << end();
   products.resize(1);
@@ -391,13 +391,13 @@ void insert_container(const string& command, kind_of_type kind, istream& in) {
   // End container Name Refinements
   trace(9991, "parse") << "--- defining " << command << ' ' << name << end();
   if (Type_ordinal.find(name) == Type_ordinal.end()
-      || Type_ordinal[name] == 0) {
-    Type_ordinal[name] = Next_type_ordinal++;
+      || get(Type_ordinal, name) == 0) {
+    put(Type_ordinal, name, Next_type_ordinal++);
   }
-  trace(9999, "parse") << "type number: " << Type_ordinal[name] << end();
+  trace(9999, "parse") << "type number: " << get(Type_ordinal, name) << end();
   skip_bracket(in, "'container' must begin with '['");
-  type_info& info = Type[Type_ordinal[name]];
-  recently_added_types.push_back(Type_ordinal[name]);
+  type_info& info = get(Type, get(Type_ordinal, name));
+  recently_added_types.push_back(get(Type_ordinal, name));
   info.name = name;
   info.kind = kind;
   while (!in.eof()) {
@@ -415,10 +415,10 @@ void insert_container(const string& command, kind_of_type kind, istream& in) {
       if (Type_ordinal.find(type_name) == Type_ordinal.end()
           // types can contain integers, like for array sizes
           && !is_integer(type_name)) {
-        Type_ordinal[type_name] = Next_type_ordinal++;
+        put(Type_ordinal, type_name, Next_type_ordinal++);
       }
-      *curr_type = new type_tree(Type_ordinal[type_name]);
-      trace(9993, "parse") << "  type: " << Type_ordinal[type_name] << end();
+      *curr_type = new type_tree(get(Type_ordinal, type_name));
+      trace(9993, "parse") << "  type: " << get(Type_ordinal, type_name) << end();
     }
     info.elements.push_back(new_type);
   }
@@ -458,7 +458,7 @@ vector<type_ordinal> recently_added_types;
 recently_added_types.clear();
 :(before "End Setup")  //: for tests
 for (long long int i = 0; i < SIZE(recently_added_types); ++i) {
-  Type_ordinal.erase(Type[recently_added_types.at(i)].name);
+  Type_ordinal.erase(get(Type, recently_added_types.at(i)).name);
   // todo: why do I explicitly need to provide this?
   for (long long int j = 0; j < SIZE(Type.at(recently_added_types.at(i)).elements); ++j) {
     delete Type.at(recently_added_types.at(i)).elements.at(j);
@@ -516,13 +516,13 @@ Transform.push_back(check_invalid_types);
 
 :(code)
 void check_invalid_types(const recipe_ordinal r) {
-  for (long long int index = 0; index < SIZE(Recipe[r].steps); ++index) {
-    const instruction& inst = Recipe[r].steps.at(index);
+  for (long long int index = 0; index < SIZE(get(Recipe, r).steps); ++index) {
+    const instruction& inst = get(Recipe, r).steps.at(index);
     for (long long int i = 0; i < SIZE(inst.ingredients); ++i) {
-      check_invalid_types(inst.ingredients.at(i).type, maybe(Recipe[r].name), "'"+inst.to_string()+"'");
+      check_invalid_types(inst.ingredients.at(i).type, maybe(get(Recipe, r).name), "'"+inst.to_string()+"'");
     }
     for (long long int i = 0; i < SIZE(inst.products); ++i) {
-      check_invalid_types(inst.products.at(i).type, maybe(Recipe[r].name), "'"+inst.to_string()+"'");
+      check_invalid_types(inst.products.at(i).type, maybe(get(Recipe, r).name), "'"+inst.to_string()+"'");
     }
   }
 }
@@ -530,7 +530,7 @@ void check_invalid_types(const recipe_ordinal r) {
 void check_invalid_types(const type_tree* type, const string& block, const string& name) {
   if (!type) return;  // will throw a more precise error elsewhere
   // End Container Type Checks
-  if (type->value && (Type.find(type->value) == Type.end() || Type[type->value].name.empty())) {
+  if (type->value && (Type.find(type->value) == Type.end() || get(Type, type->value).name.empty())) {
     raise_error << block << "unknown type in " << name << '\n' << end();
   }
   if (type->left) check_invalid_types(type->left, block, name);
@@ -576,7 +576,7 @@ void check_container_field_types() {
 :(before "End Primitive Recipe Declarations")
 MERGE,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["merge"] = MERGE;
+put(Recipe_ordinal, "merge", MERGE);
 :(before "End Primitive Recipe Checks")
 case MERGE: {
   break;
diff --git a/031address.cc b/031address.cc
index 2478de03..306621f1 100644
--- a/031address.cc
+++ b/031address.cc
@@ -48,15 +48,15 @@ void canonize(reagent& x) {
 }
 
 void lookup_memory(reagent& x) {
-  if (!x.type || x.type->value != Type_ordinal["address"]) {
+  if (!x.type || x.type->value != get(Type_ordinal, "address")) {
     raise_error << maybe(current_recipe_name()) << "tried to /lookup " << x.original_string << " but it isn't an address\n" << end();
   }
   // compute value
   if (x.value == 0) {
     raise_error << maybe(current_recipe_name()) << "tried to /lookup 0\n" << end();
   }
-  trace(9999, "mem") << "location " << x.value << " is " << no_scientific(Memory[x.value]) << end();
-  x.set_value(Memory[x.value]);
+  trace(9999, "mem") << "location " << x.value << " is " << no_scientific(get_or_insert(Memory, x.value)) << end();
+  x.set_value(get_or_insert(Memory, x.value));
   drop_address_from_type(x);
   drop_one_lookup(x);
 }
@@ -77,7 +77,7 @@ void lookup_memory(reagent& x) {
 :(code)
 bool canonize_type(reagent& r) {
   while (has_property(r, "lookup")) {
-    if (!r.type || r.type->value != Type_ordinal["address"]) {
+    if (!r.type || r.type->value != get(Type_ordinal, "address")) {
       raise_error << "can't lookup non-address: " << r.original_string << '\n' << end();
       return false;
     }
@@ -184,12 +184,12 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 _DUMP,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$dump"] = _DUMP;
+put(Recipe_ordinal, "$dump", _DUMP);
 :(before "End Primitive Recipe Implementations")
 case _DUMP: {
   reagent after_canonize = current_instruction().ingredients.at(0);
   canonize(after_canonize);
-  cerr << maybe(current_recipe_name()) << current_instruction().ingredients.at(0).name << ' ' << no_scientific(current_instruction().ingredients.at(0).value) << " => " << no_scientific(after_canonize.value) << " => " << no_scientific(Memory[after_canonize.value]) << '\n';
+  cerr << maybe(current_recipe_name()) << current_instruction().ingredients.at(0).name << ' ' << no_scientific(current_instruction().ingredients.at(0).value) << " => " << no_scientific(after_canonize.value) << " => " << no_scientific(get_or_insert(Memory, after_canonize.value)) << '\n';
   break;
 }
 
@@ -200,11 +200,11 @@ long long int foo = -1;
 :(before "End Primitive Recipe Declarations")
 _FOO,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$foo"] = _FOO;
+put(Recipe_ordinal, "$foo", _FOO);
 :(before "End Primitive Recipe Implementations")
 case _FOO: {
   if (current_instruction().ingredients.empty()) {
-    if (foo != -1) cerr << foo << ": " << no_scientific(Memory[foo]) << '\n';
+    if (foo != -1) cerr << foo << ": " << no_scientific(get_or_insert(Memory, foo)) << '\n';
     else cerr << '\n';
   }
   else {
diff --git a/032array.cc b/032array.cc
index 38b333b5..e2bc4ae2 100644
--- a/032array.cc
+++ b/032array.cc
@@ -16,30 +16,30 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 CREATE_ARRAY,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["create-array"] = CREATE_ARRAY;
+put(Recipe_ordinal, "create-array", CREATE_ARRAY);
 :(before "End Primitive Recipe Checks")
 case CREATE_ARRAY: {
   if (inst.products.empty()) {
-    raise_error << maybe(Recipe[r].name) << "'create-array' needs one product and no ingredients but got '" << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'create-array' needs one product and no ingredients but got '" << inst.to_string() << '\n' << end();
     break;
   }
   reagent product = inst.products.at(0);
   canonize_type(product);
   if (!is_mu_array(product)) {
-    raise_error << maybe(Recipe[r].name) << "'create-array' cannot create non-array " << product.original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'create-array' cannot create non-array " << product.original_string << '\n' << end();
     break;
   }
   if (!product.type->right) {
-    raise_error << maybe(Recipe[r].name) << "create array of what? " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "create array of what? " << inst.to_string() << '\n' << end();
     break;
   }
   // 'create-array' will need to check properties rather than types
   if (!product.properties.at(0).second || !product.properties.at(0).second->right || !product.properties.at(0).second->right->right) {
-    raise_error << maybe(Recipe[r].name) << "create array of what size? " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "create array of what size? " << inst.to_string() << '\n' << end();
     break;
   }
   if (!is_integer(product.properties.at(0).second->right->right->value)) {
-    raise_error << maybe(Recipe[r].name) << "'create-array' product should specify size of array after its element type, but got " << product.properties.at(0).second->right->right->value << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'create-array' product should specify size of array after its element type, but got " << product.properties.at(0).second->right->right->value << '\n' << end();
     break;
   }
   break;
@@ -51,12 +51,12 @@ case CREATE_ARRAY: {
   long long int base_address = product.value;
   long long int array_size = to_integer(product.properties.at(0).second->right->right->value);
   // initialize array size, so that size_of will work
-  Memory[base_address] = array_size;  // in array elements
+  put(Memory, base_address, array_size);  // in array elements
   long long int size = size_of(product);  // in locations
   trace(9998, "run") << "creating array of size " << size << '\n' << end();
   // initialize array
   for (long long int i = 1; i <= size_of(product); ++i) {
-    Memory[base_address+i] = 0;
+    put(Memory, base_address+i, 0);
   }
   // dummy product; doesn't actually do anything
   products.resize(1);
@@ -105,15 +105,15 @@ recipe main [
 
 //: disable the size mismatch check since the destination array need not be initialized
 :(before "End size_mismatch(x) Cases")
-if (x.type && x.type->value == Type_ordinal["array"]) return false;
+if (x.type && x.type->value == get(Type_ordinal, "array")) return false;
 :(before "End size_of(reagent) Cases")
-if (r.type && r.type->value == Type_ordinal["array"]) {
+if (r.type && r.type->value == get(Type_ordinal, "array")) {
   if (!r.type->right) {
     raise_error << maybe(current_recipe_name()) << "'" << r.original_string << "' is an array of what?\n" << end();
     return 1;
   }
   // skip the 'array' type to get at the element type
-  return 1 + Memory[r.value]*size_of(array_element(r.type));
+  return 1 + get_or_insert(Memory, r.value)*size_of(array_element(r.type));
 }
 
 //:: To access elements of an array, use 'index'
@@ -142,17 +142,17 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 INDEX,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["index"] = INDEX;
+put(Recipe_ordinal, "index", INDEX);
 :(before "End Primitive Recipe Checks")
 case INDEX: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(Recipe[r].name) << "'index' expects exactly 2 ingredients in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'index' expects exactly 2 ingredients in '" << inst.to_string() << "'\n" << end();
     break;
   }
   reagent base = inst.ingredients.at(0);
   canonize_type(base);
   if (!is_mu_array(base)) {
-    raise_error << maybe(Recipe[r].name) << "'index' on a non-array " << base.original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'index' on a non-array " << base.original_string << '\n' << end();
     break;
   }
   if (inst.products.empty()) break;
@@ -161,7 +161,7 @@ case INDEX: {
   reagent element;
   element.type = new type_tree(*array_element(base.type));
   if (!types_match(product, element)) {
-    raise_error << maybe(Recipe[r].name) << "'index' on " << base.original_string << " can't be saved in " << product.original_string << "; type should be " << dump_types(element) << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'index' on " << base.original_string << " can't be saved in " << product.original_string << "; type should be " << dump_types(element) << '\n' << end();
     break;
   }
   break;
@@ -179,13 +179,13 @@ case INDEX: {
   canonize(offset);
   vector<double> offset_val(read_memory(offset));
   type_tree* element_type = array_element(base.type);
-  if (offset_val.at(0) < 0 || offset_val.at(0) >= Memory[base_address]) {
+  if (offset_val.at(0) < 0 || offset_val.at(0) >= get_or_insert(Memory, base_address)) {
     raise_error << maybe(current_recipe_name()) << "invalid index " << no_scientific(offset_val.at(0)) << '\n' << end();
     break;
   }
   long long int src = base_address + 1 + offset_val.at(0)*size_of(element_type);
   trace(9998, "run") << "address to copy is " << src << end();
-  trace(9998, "run") << "its type is " << Type[element_type->value].name << end();
+  trace(9998, "run") << "its type is " << get(Type, element_type->value).name << end();
   reagent tmp;
   tmp.set_value(src);
   tmp.type = new type_tree(*element_type);
@@ -269,17 +269,17 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 INDEX_ADDRESS,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["index-address"] = INDEX_ADDRESS;
+put(Recipe_ordinal, "index-address", INDEX_ADDRESS);
 :(before "End Primitive Recipe Checks")
 case INDEX_ADDRESS: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(Recipe[r].name) << "'index-address' expects exactly 2 ingredients in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'index-address' expects exactly 2 ingredients in '" << inst.to_string() << "'\n" << end();
     break;
   }
   reagent base = inst.ingredients.at(0);
   canonize_type(base);
   if (!is_mu_array(base)) {
-    raise_error << maybe(Recipe[r].name) << "'index-address' on a non-array " << base.original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'index-address' on a non-array " << base.original_string << '\n' << end();
     break;
   }
   if (inst.products.empty()) break;
@@ -287,9 +287,9 @@ case INDEX_ADDRESS: {
   canonize_type(product);
   reagent element;
   element.type = new type_tree(*array_element(base.type));
-  element.type = new type_tree(Type_ordinal["address"], element.type);
+  element.type = new type_tree(get(Type_ordinal, "address"), element.type);
   if (!types_match(product, element)) {
-    raise_error << maybe(Recipe[r].name) << "'index' on " << base.original_string << " can't be saved in " << product.original_string << "; type should be " << dump_types(element) << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'index' on " << base.original_string << " can't be saved in " << product.original_string << "; type should be " << dump_types(element) << '\n' << end();
     break;
   }
   break;
@@ -307,7 +307,7 @@ case INDEX_ADDRESS: {
   canonize(offset);
   vector<double> offset_val(read_memory(offset));
   type_tree* element_type = array_element(base.type);
-  if (offset_val.at(0) < 0 || offset_val.at(0) >= Memory[base_address]) {
+  if (offset_val.at(0) < 0 || offset_val.at(0) >= get_or_insert(Memory, base_address)) {
     raise_error << maybe(current_recipe_name()) << "invalid index " << no_scientific(offset_val.at(0)) << '\n' << end();
     break;
   }
@@ -377,11 +377,11 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 LENGTH,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["length"] = LENGTH;
+put(Recipe_ordinal, "length", LENGTH);
 :(before "End Primitive Recipe Checks")
 case LENGTH: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(Recipe[r].name) << "'length' expects exactly 2 ingredients in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'length' expects exactly 2 ingredients in '" << inst.to_string() << "'\n" << end();
     break;
   }
   reagent x = inst.ingredients.at(0);
@@ -401,7 +401,7 @@ case LENGTH: {
     break;
   }
   products.resize(1);
-  products.at(0).push_back(Memory[x.value]);
+  products.at(0).push_back(get_or_insert(Memory, x.value));
   break;
 }
 
diff --git a/033exclusive_container.cc b/033exclusive_container.cc
index ac7bcfd4..bf14d9d7 100644
--- a/033exclusive_container.cc
+++ b/033exclusive_container.cc
@@ -7,14 +7,14 @@
 :(before "End Mu Types Initialization")
 //: We'll use this container as a running example, with two number elements.
 {
-type_ordinal tmp = Type_ordinal["number-or-point"] = Next_type_ordinal++;
-Type[tmp].size = 2;
-Type[tmp].kind = EXCLUSIVE_CONTAINER;
-Type[tmp].name = "number-or-point";
-Type[tmp].elements.push_back(new type_tree(number));
-Type[tmp].element_names.push_back("i");
-Type[tmp].elements.push_back(new type_tree(point));
-Type[tmp].element_names.push_back("p");
+type_ordinal tmp = put(Type_ordinal, "number-or-point", Next_type_ordinal++);
+get(Type, tmp).size = 2;
+get(Type, tmp).kind = EXCLUSIVE_CONTAINER;
+get(Type, tmp).name = "number-or-point";
+get(Type, tmp).elements.push_back(new type_tree(number));
+get(Type, tmp).element_names.push_back("i");
+get(Type, tmp).elements.push_back(new type_tree(point));
+get(Type, tmp).element_names.push_back("p");
 }
 
 //: Tests in this layer often explicitly setup memory before reading it as an
@@ -53,7 +53,7 @@ if (t.kind == EXCLUSIVE_CONTAINER) {
 //: 'maybe-convert' requires a literal in ingredient 1. We'll use a synonym
 //: called 'variant'.
 :(before "End Mu Types Initialization")
-Type_ordinal["variant"] = 0;
+put(Type_ordinal, "variant", 0);
 
 :(scenario maybe_convert)
 recipe main [
@@ -76,21 +76,21 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 MAYBE_CONVERT,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["maybe-convert"] = MAYBE_CONVERT;
+put(Recipe_ordinal, "maybe-convert", MAYBE_CONVERT);
 :(before "End Primitive Recipe Checks")
 case MAYBE_CONVERT: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(Recipe[r].name) << "'maybe-convert' expects exactly 2 ingredients in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'maybe-convert' expects exactly 2 ingredients in '" << inst.to_string() << "'\n" << end();
     break;
   }
   reagent base = inst.ingredients.at(0);
   canonize_type(base);
-  if (!base.type || !base.type->value || Type[base.type->value].kind != EXCLUSIVE_CONTAINER) {
-    raise_error << maybe(Recipe[r].name) << "first ingredient of 'maybe-convert' should be an exclusive-container, but got " << base.original_string << '\n' << end();
+  if (!base.type || !base.type->value || get(Type, base.type->value).kind != EXCLUSIVE_CONTAINER) {
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'maybe-convert' should be an exclusive-container, but got " << base.original_string << '\n' << end();
     break;
   }
   if (!is_literal(inst.ingredients.at(1))) {
-    raise_error << maybe(Recipe[r].name) << "second ingredient of 'maybe-convert' should have type 'variant', but got " << inst.ingredients.at(1).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "second ingredient of 'maybe-convert' should have type 'variant', but got " << inst.ingredients.at(1).original_string << '\n' << end();
     break;
   }
   break;
@@ -106,7 +106,7 @@ case MAYBE_CONVERT: {
   }
   long long int tag = current_instruction().ingredients.at(1).value;
   long long int result;
-  if (tag == static_cast<long long int>(Memory[base_address])) {
+  if (tag == static_cast<long long int>(get_or_insert(Memory, base_address))) {
     result = base_address+1;
   }
   else {
@@ -160,7 +160,7 @@ if (current_instruction().operation == MERGE
     && current_instruction().products.at(0).type) {
   reagent x = current_instruction().products.at(0);
   canonize(x);
-  if (Type[x.type->value].kind == EXCLUSIVE_CONTAINER) {
+  if (get(Type, x.type->value).kind == EXCLUSIVE_CONTAINER) {
     return size_of(x) < SIZE(data);
   }
 }
diff --git a/034call.cc b/034call.cc
index b6793c72..80d142d7 100644
--- a/034call.cc
+++ b/034call.cc
@@ -82,7 +82,7 @@ inline long long int& current_step_index() {
 :(replace{} "inline const string& current_recipe_name()")
 inline const string& current_recipe_name() {
   assert(!Current_routine->calls.empty());
-  return Recipe[current_call().running_recipe].name;
+  return get(Recipe, current_call().running_recipe).name;
 }
 :(replace{} "inline const instruction& current_instruction()")
 inline const instruction& current_instruction() {
@@ -91,13 +91,13 @@ inline const instruction& current_instruction() {
 }
 :(code)
 inline const instruction& to_instruction(const call& call) {
-  return Recipe[call.running_recipe].steps.at(call.running_step_index);
+  return get(Recipe, call.running_recipe).steps.at(call.running_step_index);
 }
 
 :(after "Defined Recipe Checks")
 // not a primitive; check that it's present in the book of recipes
 if (Recipe.find(inst.operation) == Recipe.end()) {
-  raise_error << maybe(Recipe[r].name) << "undefined operation in '" << inst.to_string() << "'\n" << end();
+  raise_error << maybe(get(Recipe, r).name) << "undefined operation in '" << inst.to_string() << "'\n" << end();
   break;
 }
 :(replace{} "default:" following "End Primitive Recipe Implementations")
@@ -142,7 +142,7 @@ inline bool routine::completed() const {
 
 inline const vector<instruction>& routine::steps() const {
   assert(!calls.empty());
-  return Recipe[calls.front().running_recipe].steps;
+  return get(Recipe, calls.front().running_recipe).steps;
 }
 
 :(before "Running One Instruction")
diff --git a/035call_ingredient.cc b/035call_ingredient.cc
index eb899899..6bba2b23 100644
--- a/035call_ingredient.cc
+++ b/035call_ingredient.cc
@@ -43,11 +43,11 @@ for (long long int i = 0; i < SIZE(ingredient_types); ++i) {
 :(before "End Primitive Recipe Declarations")
 NEXT_INGREDIENT,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["next-ingredient"] = NEXT_INGREDIENT;
+put(Recipe_ordinal, "next-ingredient", NEXT_INGREDIENT);
 :(before "End Primitive Recipe Checks")
 case NEXT_INGREDIENT: {
   if (!inst.ingredients.empty()) {
-    raise_error << maybe(Recipe[r].name) << "'next-ingredient' didn't expect any ingredients in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'next-ingredient' didn't expect any ingredients in '" << inst.to_string() << "'\n" << end();
     break;
   }
   break;
@@ -113,7 +113,7 @@ recipe f [
 :(before "End Primitive Recipe Declarations")
 REWIND_INGREDIENTS,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["rewind-ingredients"] = REWIND_INGREDIENTS;
+put(Recipe_ordinal, "rewind-ingredients", REWIND_INGREDIENTS);
 :(before "End Primitive Recipe Checks")
 case REWIND_INGREDIENTS: {
   break;
@@ -138,15 +138,15 @@ recipe f [
 :(before "End Primitive Recipe Declarations")
 INGREDIENT,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["ingredient"] = INGREDIENT;
+put(Recipe_ordinal, "ingredient", INGREDIENT);
 :(before "End Primitive Recipe Checks")
 case INGREDIENT: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(Recipe[r].name) << "'ingredient' expects exactly one ingredient, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'ingredient' expects exactly one ingredient, but got '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!is_literal(inst.ingredients.at(0)) && !is_mu_number(inst.ingredients.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "'ingredient' expects a literal ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'ingredient' expects a literal ingredient, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   break;
diff --git a/036call_reply.cc b/036call_reply.cc
index e43a704c..695c0910 100644
--- a/036call_reply.cc
+++ b/036call_reply.cc
@@ -15,7 +15,7 @@ recipe f [
 :(before "End Primitive Recipe Declarations")
 REPLY,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["reply"] = REPLY;
+put(Recipe_ordinal, "reply", REPLY);
 :(before "End Primitive Recipe Checks")
 case REPLY: {
   break;  // continue to process rest of *caller* instruction
@@ -173,7 +173,7 @@ recipe test1 [
 //   ```
 if (curr.name == "reply-if") {
   if (curr.products.empty()) {
-    curr.operation = Recipe_ordinal["jump-unless"];
+    curr.operation = get(Recipe_ordinal, "jump-unless");
     curr.name = "jump-unless";
     vector<reagent> results;
     copy(++curr.ingredients.begin(), curr.ingredients.end(), inserter(results, results.end()));
@@ -181,7 +181,7 @@ if (curr.name == "reply-if") {
     curr.ingredients.push_back(reagent("1:offset"));
     result.steps.push_back(curr);
     curr.clear();
-    curr.operation = Recipe_ordinal["reply"];
+    curr.operation = get(Recipe_ordinal, "reply");
     curr.name = "reply";
     curr.ingredients.swap(results);
   }
@@ -196,7 +196,7 @@ if (curr.name == "reply-if") {
 //   ```
 if (curr.name == "reply-unless") {
   if (curr.products.empty()) {
-    curr.operation = Recipe_ordinal["jump-if"];
+    curr.operation = get(Recipe_ordinal, "jump-if");
     curr.name = "jump-if";
     vector<reagent> results;
     copy(++curr.ingredients.begin(), curr.ingredients.end(), inserter(results, results.end()));
@@ -204,7 +204,7 @@ if (curr.name == "reply-unless") {
     curr.ingredients.push_back(reagent("1:offset"));
     result.steps.push_back(curr);
     curr.clear();
-    curr.operation = Recipe_ordinal["reply"];
+    curr.operation = get(Recipe_ordinal, "reply");
     curr.name = "reply";
     curr.ingredients.swap(results);
   }
diff --git a/037recipe.cc b/037recipe.cc
index a2a95a39..0a4fea4e 100644
--- a/037recipe.cc
+++ b/037recipe.cc
@@ -4,22 +4,22 @@
 
 :(before "End Mu Types Initialization")
 // 'recipe' is a literal
-Type_ordinal["recipe"] = 0;
+put(Type_ordinal, "recipe", 0);
 // 'recipe-ordinal' is the literal that can store recipe literals
-type_ordinal recipe_ordinal = Type_ordinal["recipe-ordinal"] = Next_type_ordinal++;
-Type[recipe_ordinal].name = "recipe-ordinal";
+type_ordinal recipe_ordinal = put(Type_ordinal, "recipe-ordinal", Next_type_ordinal++);
+get(Type, recipe_ordinal).name = "recipe-ordinal";
 
 :(before "End Reagent-parsing Exceptions")
 if (r.properties.at(0).second && r.properties.at(0).second->value == "recipe") {
-  r.set_value(Recipe_ordinal[r.name]);
+  r.set_value(get(Recipe_ordinal, r.name));
   return;
 }
 
 :(code)
 bool is_mu_recipe(reagent r) {
   if (!r.type) return false;
-  if (r.type->value == Type_ordinal["recipe"]) return true;
-  if (r.type->value == Type_ordinal["recipe-ordinal"]) return true;
+  if (r.type->value == get(Type_ordinal, "recipe")) return true;
+  if (r.type->value == get(Type_ordinal, "recipe-ordinal")) return true;
   // End is_mu_recipe Cases
   return false;
 }
diff --git a/038scheduler.cc b/038scheduler.cc
index 1b482fc5..34a6df8d 100644
--- a/038scheduler.cc
+++ b/038scheduler.cc
@@ -97,7 +97,7 @@ string current_routine_label() {
   const call_stack& calls = Current_routine->calls;
   for (call_stack::const_iterator p = calls.begin(); p != calls.end(); ++p) {
     if (p != calls.begin()) result << '/';
-    result << Recipe[p->running_recipe].name;
+    result << get(Recipe, p->running_recipe).name;
   }
   return result.str();
 }
@@ -111,7 +111,7 @@ Current_routine = NULL;
 //: special case for the very first routine
 :(replace{} "void run_main(int argc, char* argv[])")
 void run_main(int argc, char* argv[]) {
-  recipe_ordinal r = Recipe_ordinal[string("main")];
+  recipe_ordinal r = get(Recipe_ordinal, string("main"));
   if (r) {
     routine* main_routine = new routine(r);
     // Update main_routine
@@ -143,15 +143,15 @@ parent_index = -1;
 :(before "End Primitive Recipe Declarations")
 START_RUNNING,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["start-running"] = START_RUNNING;
+put(Recipe_ordinal, "start-running", START_RUNNING);
 :(before "End Primitive Recipe Checks")
 case START_RUNNING: {
   if (inst.ingredients.empty()) {
-    raise_error << maybe(Recipe[r].name) << "'start-running' requires at least one ingredient: the recipe to start running\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'start-running' requires at least one ingredient: the recipe to start running\n" << end();
     break;
   }
   if (!is_mu_recipe(inst.ingredients.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "first ingredient of 'start-running' should be a recipe, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'start-running' should be a recipe, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -334,15 +334,15 @@ recipe f2 [
 :(before "End Primitive Recipe Declarations")
 ROUTINE_STATE,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["routine-state"] = ROUTINE_STATE;
+put(Recipe_ordinal, "routine-state", ROUTINE_STATE);
 :(before "End Primitive Recipe Checks")
 case ROUTINE_STATE: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(Recipe[r].name) << "'routine-state' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'routine-state' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "first ingredient of 'routine-state' should be a routine id generated by 'start-running', but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'routine-state' should be a routine id generated by 'start-running', but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -367,15 +367,15 @@ case ROUTINE_STATE: {
 :(before "End Primitive Recipe Declarations")
 RESTART,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["restart"] = RESTART;
+put(Recipe_ordinal, "restart", RESTART);
 :(before "End Primitive Recipe Checks")
 case RESTART: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(Recipe[r].name) << "'restart' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'restart' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "first ingredient of 'restart' should be a routine id generated by 'start-running', but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'restart' should be a routine id generated by 'start-running', but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -395,15 +395,15 @@ case RESTART: {
 :(before "End Primitive Recipe Declarations")
 STOP,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["stop"] = STOP;
+put(Recipe_ordinal, "stop", STOP);
 :(before "End Primitive Recipe Checks")
 case STOP: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(Recipe[r].name) << "'stop' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'stop' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "first ingredient of 'stop' should be a routine id generated by 'start-running', but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'stop' should be a routine id generated by 'start-running', but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -423,7 +423,7 @@ case STOP: {
 :(before "End Primitive Recipe Declarations")
 _DUMP_ROUTINES,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$dump-routines"] = _DUMP_ROUTINES;
+put(Recipe_ordinal, "$dump-routines", _DUMP_ROUTINES);
 :(before "End Primitive Recipe Checks")
 case _DUMP_ROUTINES: {
   break;
@@ -477,19 +477,19 @@ limit = -1;  /* no limit */
 :(before "End Primitive Recipe Declarations")
 LIMIT_TIME,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["limit-time"] = LIMIT_TIME;
+put(Recipe_ordinal, "limit-time", LIMIT_TIME);
 :(before "End Primitive Recipe Checks")
 case LIMIT_TIME: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(Recipe[r].name) << "'limit-time' requires exactly two ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'limit-time' requires exactly two ingredient, but got " << inst.to_string() << '\n' << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "first ingredient of 'limit-time' should be a routine id generated by 'start-running', but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'limit-time' should be a routine id generated by 'start-running', but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(1))) {
-    raise_error << maybe(Recipe[r].name) << "second ingredient of 'limit-time' should be a number (of instructions to run for), but got " << inst.ingredients.at(1).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "second ingredient of 'limit-time' should be a number (of instructions to run for), but got " << inst.ingredients.at(1).original_string << '\n' << end();
     break;
   }
   break;
diff --git a/039wait.cc b/039wait.cc
index 27412901..ef3d30e5 100644
--- a/039wait.cc
+++ b/039wait.cc
@@ -33,7 +33,7 @@ waiting_on_location = old_value_of_waiting_location = 0;
 :(before "End Primitive Recipe Declarations")
 WAIT_FOR_LOCATION,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["wait-for-location"] = WAIT_FOR_LOCATION;
+put(Recipe_ordinal, "wait-for-location", WAIT_FOR_LOCATION);
 :(before "End Primitive Recipe Checks")
 case WAIT_FOR_LOCATION: {
   break;
@@ -44,8 +44,8 @@ case WAIT_FOR_LOCATION: {
   canonize(loc);
   Current_routine->state = WAITING;
   Current_routine->waiting_on_location = loc.value;
-  Current_routine->old_value_of_waiting_location = Memory[loc.value];
-  trace(9998, "run") << "waiting for location " << loc.value << " to change from " << no_scientific(Memory[loc.value]) << end();
+  Current_routine->old_value_of_waiting_location = get_or_insert(Memory, loc.value);
+  trace(9998, "run") << "waiting for location " << loc.value << " to change from " << no_scientific(get_or_insert(Memory, loc.value)) << end();
   break;
 }
 
@@ -55,7 +55,7 @@ case WAIT_FOR_LOCATION: {
 for (long long int i = 0; i < SIZE(Routines); ++i) {
   if (Routines.at(i)->state != WAITING) continue;
   if (Routines.at(i)->waiting_on_location &&
-      Memory[Routines.at(i)->waiting_on_location] != Routines.at(i)->old_value_of_waiting_location) {
+      get_or_insert(Memory, Routines.at(i)->waiting_on_location) != Routines.at(i)->old_value_of_waiting_location) {
     trace(9999, "schedule") << "waking up routine\n" << end();
     Routines.at(i)->state = RUNNING;
     Routines.at(i)->waiting_on_location = Routines.at(i)->old_value_of_waiting_location = 0;
@@ -92,15 +92,15 @@ waiting_on_routine = 0;
 :(before "End Primitive Recipe Declarations")
 WAIT_FOR_ROUTINE,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["wait-for-routine"] = WAIT_FOR_ROUTINE;
+put(Recipe_ordinal, "wait-for-routine", WAIT_FOR_ROUTINE);
 :(before "End Primitive Recipe Checks")
 case WAIT_FOR_ROUTINE: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(Recipe[r].name) << "'wait-for-routine' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'wait-for-routine' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "first ingredient of 'wait-for-routine' should be a routine id generated by 'start-running', but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'wait-for-routine' should be a routine id generated by 'start-running', but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -138,7 +138,7 @@ for (long long int i = 0; i < SIZE(Routines); ++i) {
 :(before "End Primitive Recipe Declarations")
 SWITCH,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["switch"] = SWITCH;
+put(Recipe_ordinal, "switch", SWITCH);
 :(before "End Primitive Recipe Checks")
 case SWITCH: {
   break;
diff --git a/040brace.cc b/040brace.cc
index 9429fe1a..670949d2 100644
--- a/040brace.cc
+++ b/040brace.cc
@@ -39,11 +39,11 @@ void transform_braces(const recipe_ordinal r) {
   const int OPEN = 0, CLOSE = 1;
   // use signed integer for step index because we'll be doing arithmetic on it
   list<pair<int/*OPEN/CLOSE*/, /*step*/long long int> > braces;
-  trace(9991, "transform") << "--- transform braces for recipe " << Recipe[r].name << end();
-  for (long long int index = 0; index < SIZE(Recipe[r].steps); ++index) {
-    const instruction& inst = Recipe[r].steps.at(index);
+  trace(9991, "transform") << "--- transform braces for recipe " << get(Recipe, r).name << end();
+  for (long long int index = 0; index < SIZE(get(Recipe, r).steps); ++index) {
+    const instruction& inst = get(Recipe, r).steps.at(index);
     if (inst.label == "{") {
-      trace(9993, "transform") << maybe(Recipe[r].name) << "push (open, " << index << ")" << end();
+      trace(9993, "transform") << maybe(get(Recipe, r).name) << "push (open, " << index << ")" << end();
       braces.push_back(pair<int,long long int>(OPEN, index));
     }
     if (inst.label == "}") {
@@ -52,15 +52,15 @@ void transform_braces(const recipe_ordinal r) {
     }
   }
   stack</*step*/long long int> open_braces;
-  for (long long int index = 0; index < SIZE(Recipe[r].steps); ++index) {
-    instruction& inst = Recipe[r].steps.at(index);
+  for (long long int index = 0; index < SIZE(get(Recipe, r).steps); ++index) {
+    instruction& inst = get(Recipe, r).steps.at(index);
     if (inst.label == "{") {
       open_braces.push(index);
       continue;
     }
     if (inst.label == "}") {
       if (open_braces.empty()) {
-        raise << "missing '{' in " << Recipe[r].name << '\n';
+        raise << "missing '{' in " << get(Recipe, r).name << '\n';
         return;
       }
       open_braces.pop();
@@ -113,7 +113,7 @@ void transform_braces(const recipe_ordinal r) {
     }
     // if implicit, compute target
     reagent target;
-    target.type = new type_tree(Type_ordinal["offset"]);
+    target.type = new type_tree(get(Type_ordinal, "offset"));
     target.set_value(0);
     if (open_braces.empty())
       raise_error << inst.old_name << " needs a '{' before\n" << end();
@@ -139,8 +139,8 @@ long long int matching_brace(long long int index, const list<pair<int, long long
     stacksize += (p->first ? 1 : -1);
     if (stacksize == 0) return p->second;
   }
-  raise_error << maybe(Recipe[r].name) << "unbalanced '{'\n" << end();
-  return SIZE(Recipe[r].steps);  // exit current routine
+  raise_error << maybe(get(Recipe, r).name) << "unbalanced '{'\n" << end();
+  return SIZE(get(Recipe, r).steps);  // exit current routine
 }
 
 :(scenario loop)
@@ -372,12 +372,12 @@ LOOP,
 LOOP_IF,
 LOOP_UNLESS,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["break"] = BREAK;
-Recipe_ordinal["break-if"] = BREAK_IF;
-Recipe_ordinal["break-unless"] = BREAK_UNLESS;
-Recipe_ordinal["loop"] = LOOP;
-Recipe_ordinal["loop-if"] = LOOP_IF;
-Recipe_ordinal["loop-unless"] = LOOP_UNLESS;
+put(Recipe_ordinal, "break", BREAK);
+put(Recipe_ordinal, "break-if", BREAK_IF);
+put(Recipe_ordinal, "break-unless", BREAK_UNLESS);
+put(Recipe_ordinal, "loop", LOOP);
+put(Recipe_ordinal, "loop-if", LOOP_IF);
+put(Recipe_ordinal, "loop-unless", LOOP_UNLESS);
 :(before "End Primitive Recipe Checks")
 case BREAK: break;
 case BREAK_IF: break;
diff --git a/041jump_target.cc b/041jump_target.cc
index d395cd97..d7ff717a 100644
--- a/041jump_target.cc
+++ b/041jump_target.cc
@@ -16,7 +16,7 @@ recipe main [
 -mem: storing 0 in location 1
 
 :(before "End Mu Types Initialization")
-Type_ordinal["label"] = 0;
+put(Type_ordinal, "label", 0);
 
 :(before "Transform.push_back(transform_braces)")
 Transform.push_back(transform_labels);
@@ -24,21 +24,21 @@ Transform.push_back(transform_labels);
 :(code)
 void transform_labels(const recipe_ordinal r) {
   map<string, long long int> offset;
-  for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
-    const instruction& inst = Recipe[r].steps.at(i);
+  for (long long int i = 0; i < SIZE(get(Recipe, r).steps); ++i) {
+    const instruction& inst = get(Recipe, r).steps.at(i);
     if (!inst.label.empty() && inst.label.at(0) == '+') {
       if (offset.find(inst.label) == offset.end()) {
         offset[inst.label] = i;
       }
       else {
-        raise_error << maybe(Recipe[r].name) << "duplicate label '" << inst.label << "'" << end();
+        raise_error << maybe(get(Recipe, r).name) << "duplicate label '" << inst.label << "'" << end();
         // have all jumps skip some random but noticeable and deterministic amount of code
         offset[inst.label] = 9999;
       }
     }
   }
-  for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
-    instruction& inst = Recipe[r].steps.at(i);
+  for (long long int i = 0; i < SIZE(get(Recipe, r).steps); ++i) {
+    instruction& inst = get(Recipe, r).steps.at(i);
     if (inst.name == "jump") {
       replace_offset(inst.ingredients.at(0), offset, i, r);
     }
@@ -60,19 +60,19 @@ void transform_labels(const recipe_ordinal r) {
 :(code)
 void replace_offset(reagent& x, /*const*/ map<string, long long int>& offset, const long long int current_offset, const recipe_ordinal r) {
   if (!is_literal(x)) {
-    raise_error << maybe(Recipe[r].name) << "jump target must be offset or label but is " << x.original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "jump target must be offset or label but is " << x.original_string << '\n' << end();
     x.set_value(0);  // no jump by default
     return;
   }
   assert(!x.initialized);
   if (is_integer(x.name)) return;  // non-labels will be handled like other number operands
   if (!is_jump_target(x.name)) {
-    raise_error << maybe(Recipe[r].name) << "can't jump to label " << x.name << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "can't jump to label " << x.name << '\n' << end();
     x.set_value(0);  // no jump by default
     return;
   }
   if (offset.find(x.name) == offset.end()) {
-    raise_error << maybe(Recipe[r].name) << "can't find label " << x.name << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "can't find label " << x.name << '\n' << end();
     x.set_value(0);  // no jump by default
     return;
   }
diff --git a/042name.cc b/042name.cc
index 0454e9dd..ae540c57 100644
--- a/042name.cc
+++ b/042name.cc
@@ -30,30 +30,30 @@ for (long long int i = 0; i < SIZE(recently_added_recipes); ++i) {
 
 :(code)
 void transform_names(const recipe_ordinal r) {
-  trace(9991, "transform") << "--- transform names for recipe " << Recipe[r].name << end();
+  trace(9991, "transform") << "--- transform names for recipe " << get(Recipe, r).name << end();
   bool names_used = false;
   bool numeric_locations_used = false;
   map<string, long long int>& names = Name[r];
   // store the indices 'used' so far in the map
   long long int& curr_idx = names[""];
   ++curr_idx;  // avoid using index 0, benign skip in some other cases
-  for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
-    instruction& inst = Recipe[r].steps.at(i);
+  for (long long int i = 0; i < SIZE(get(Recipe, r).steps); ++i) {
+    instruction& inst = get(Recipe, r).steps.at(i);
     // End transform_names(inst) Special-cases
     // map names to addresses
     for (long long int in = 0; in < SIZE(inst.ingredients); ++in) {
       if (is_numeric_location(inst.ingredients.at(in))) numeric_locations_used = true;
       if (is_named_location(inst.ingredients.at(in))) names_used = true;
-      if (disqualified(inst.ingredients.at(in), inst, Recipe[r].name)) continue;
+      if (disqualified(inst.ingredients.at(in), inst, get(Recipe, r).name)) continue;
       if (!already_transformed(inst.ingredients.at(in), names)) {
-        raise_error << maybe(Recipe[r].name) << "use before set: " << inst.ingredients.at(in).name << '\n' << end();
+        raise_error << maybe(get(Recipe, r).name) << "use before set: " << inst.ingredients.at(in).name << '\n' << end();
       }
       inst.ingredients.at(in).set_value(lookup_name(inst.ingredients.at(in), r));
     }
     for (long long int out = 0; out < SIZE(inst.products); ++out) {
       if (is_numeric_location(inst.products.at(out))) numeric_locations_used = true;
       if (is_named_location(inst.products.at(out))) names_used = true;
-      if (disqualified(inst.products.at(out), inst, Recipe[r].name)) continue;
+      if (disqualified(inst.products.at(out), inst, get(Recipe, r).name)) continue;
       if (names.find(inst.products.at(out).name) == names.end()) {
         trace(9993, "name") << "assign " << inst.products.at(out).name << " " << curr_idx << end();
         names[inst.products.at(out).name] = curr_idx;
@@ -63,7 +63,7 @@ void transform_names(const recipe_ordinal r) {
     }
   }
   if (names_used && numeric_locations_used)
-    raise_error << maybe(Recipe[r].name) << "mixing variable names and numeric addresses\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "mixing variable names and numeric addresses\n" << end();
 }
 
 bool disqualified(/*mutable*/ reagent& x, const instruction& inst, const string& recipe_name) {
@@ -89,7 +89,7 @@ long long int lookup_name(const reagent& r, const recipe_ordinal default_recipe)
 
 type_ordinal skip_addresses(type_tree* type, const string& recipe_name) {
   for (; type; type = type->right) {
-    if (type->value != Type_ordinal["address"])
+    if (type->value != get(Type_ordinal, "address"))
       return type->value;
   }
   raise_error << maybe(recipe_name) << "expected a container" << '\n' << end();
@@ -97,11 +97,11 @@ type_ordinal skip_addresses(type_tree* type, const string& recipe_name) {
 }
 
 int find_element_name(const type_ordinal t, const string& name, const string& recipe_name) {
-  const type_info& container = Type[t];
+  const type_info& container = get(Type, t);
   for (long long int i = 0; i < SIZE(container.element_names); ++i) {
     if (container.element_names.at(i) == name) return i;
   }
-  raise_error << maybe(recipe_name) << "unknown element " << name << " in container " << Type[t].name << '\n' << end();
+  raise_error << maybe(recipe_name) << "unknown element " << name << " in container " << get(Type, t).name << '\n' << end();
   return -1;
 }
 
@@ -180,8 +180,8 @@ $error: 0
 
 //: update our running example container for the next test
 :(before "End Mu Types Initialization")
-Type[point].element_names.push_back("x");
-Type[point].element_names.push_back("y");
+get(Type, point).element_names.push_back("x");
+get(Type, point).element_names.push_back("y");
 :(scenario transform_names_transforms_container_elements)
 recipe main [
   p:address:point <- copy 0  # unsafe
@@ -195,16 +195,16 @@ recipe main [
 // replace element names of containers with offsets
 if (inst.name == "get" || inst.name == "get-address") {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(Recipe[r].name) << "exactly 2 ingredients expected in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "exactly 2 ingredients expected in '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!is_literal(inst.ingredients.at(1)))
-    raise_error << maybe(Recipe[r].name) << "expected ingredient 1 of " << (inst.name == "get" ? "'get'" : "'get-address'") << " to have type 'offset'; got " << inst.ingredients.at(1).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "expected ingredient 1 of " << (inst.name == "get" ? "'get'" : "'get-address'") << " to have type 'offset'; got " << inst.ingredients.at(1).original_string << '\n' << end();
   if (inst.ingredients.at(1).name.find_first_not_of("0123456789") != string::npos) {
     // since first non-address in base type must be a container, we don't have to canonize
-    type_ordinal base_type = skip_addresses(inst.ingredients.at(0).type, Recipe[r].name);
-    inst.ingredients.at(1).set_value(find_element_name(base_type, inst.ingredients.at(1).name, Recipe[r].name));
-    trace(9993, "name") << "element " << inst.ingredients.at(1).name << " of type " << Type[base_type].name << " is at offset " << no_scientific(inst.ingredients.at(1).value) << end();
+    type_ordinal base_type = skip_addresses(inst.ingredients.at(0).type, get(Recipe, r).name);
+    inst.ingredients.at(1).set_value(find_element_name(base_type, inst.ingredients.at(1).name, get(Recipe, r).name));
+    trace(9993, "name") << "element " << inst.ingredients.at(1).name << " of type " << get(Type, base_type).name << " is at offset " << no_scientific(inst.ingredients.at(1).value) << end();
   }
 }
 
@@ -235,14 +235,14 @@ recipe main [
 // convert variant names of exclusive containers
 if (inst.name == "maybe-convert") {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(Recipe[r].name) << "exactly 2 ingredients expected in '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "exactly 2 ingredients expected in '" << inst.to_string() << "'\n" << end();
     break;
   }
   assert(is_literal(inst.ingredients.at(1)));
   if (inst.ingredients.at(1).name.find_first_not_of("0123456789") != string::npos) {
     // since first non-address in base type must be an exclusive container, we don't have to canonize
-    type_ordinal base_type = skip_addresses(inst.ingredients.at(0).type, Recipe[r].name);
-    inst.ingredients.at(1).set_value(find_element_name(base_type, inst.ingredients.at(1).name, Recipe[r].name));
-    trace(9993, "name") << "variant " << inst.ingredients.at(1).name << " of type " << Type[base_type].name << " has tag " << no_scientific(inst.ingredients.at(1).value) << end();
+    type_ordinal base_type = skip_addresses(inst.ingredients.at(0).type, get(Recipe, r).name);
+    inst.ingredients.at(1).set_value(find_element_name(base_type, inst.ingredients.at(1).name, get(Recipe, r).name));
+    trace(9993, "name") << "variant " << inst.ingredients.at(1).name << " of type " << get(Type, base_type).name << " has tag " << no_scientific(inst.ingredients.at(1).value) << end();
   }
 }
diff --git a/043new.cc b/043new.cc
index a851e3d5..752ee323 100644
--- a/043new.cc
+++ b/043new.cc
@@ -26,23 +26,23 @@ trace(9999, "new") << "routine allocated memory from " << alloc << " to " << all
 
 //:: 'new' takes a weird 'type' as its first ingredient; don't error on it
 :(before "End Mu Types Initialization")
-Type_ordinal["type"] = 0;
+put(Type_ordinal, "type", 0);
 
 //:: typecheck 'new' instructions
 :(before "End Primitive Recipe Declarations")
 NEW,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["new"] = NEW;
+put(Recipe_ordinal, "new", NEW);
 :(before "End Primitive Recipe Checks")
 case NEW: {
   if (inst.ingredients.empty() || SIZE(inst.ingredients) > 2) {
-    raise_error << maybe(Recipe[r].name) << "'new' requires one or two ingredients, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'new' requires one or two ingredients, but got " << inst.to_string() << '\n' << end();
     break;
   }
   // End NEW Check Special-cases
   reagent type = inst.ingredients.at(0);
   if (!is_mu_type_literal(type)) {
-    raise_error << maybe(Recipe[r].name) << "first ingredient of 'new' should be a type, but got " << type.original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'new' should be a type, but got " << type.original_string << '\n' << end();
     break;
   }
   break;
@@ -54,9 +54,9 @@ Transform.push_back(transform_new_to_allocate);
 
 :(code)
 void transform_new_to_allocate(recipe_ordinal r) {
-  trace(9991, "transform") << "--- convert 'new' to 'allocate' for recipe " << Recipe[r].name << end();
-  for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
-    instruction& inst = Recipe[r].steps.at(i);
+  trace(9991, "transform") << "--- convert 'new' to 'allocate' for recipe " << get(Recipe, r).name << end();
+  for (long long int i = 0; i < SIZE(get(Recipe, r).steps); ++i) {
+    instruction& inst = get(Recipe, r).steps.at(i);
     // Convert 'new' To 'allocate'
     if (inst.name == "new") {
       inst.operation = ALLOCATE;
@@ -80,7 +80,7 @@ void transform_new_to_allocate(recipe_ordinal r) {
 :(before "End Primitive Recipe Declarations")
 ALLOCATE,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["allocate"] = ALLOCATE;
+put(Recipe_ordinal, "allocate", ALLOCATE);
 :(before "End Primitive Recipe Implementations")
 case ALLOCATE: {
   // compute the space we need
@@ -102,10 +102,10 @@ case ALLOCATE: {
   products.at(0).push_back(result);
   // initialize allocated space
   for (long long int address = result; address < result+size; ++address) {
-    Memory[address] = 0;
+    put(Memory, address, 0);
   }
   if (SIZE(current_instruction().ingredients) > 1) {
-    Memory[result] = ingredients.at(1).at(0);  // array length
+    put(Memory, result, ingredients.at(1).at(0));  // array length
   }
   // bump
   Current_routine->alloc += size;
@@ -158,7 +158,7 @@ void ensure_space(long long int size) {
 
 :(scenario new_initializes)
 % Memory_allocated_until = 10;
-% Memory[Memory_allocated_until] = 1;
+% put(Memory, Memory_allocated_until, 1);
 recipe main [
   1:address:number <- new number:type
   2:number <- copy *1:address:number
@@ -236,17 +236,17 @@ Free_list.clear();
 :(before "End Primitive Recipe Declarations")
 ABANDON,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["abandon"] = ABANDON;
+put(Recipe_ordinal, "abandon", ABANDON);
 :(before "End Primitive Recipe Checks")
 case ABANDON: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(Recipe[r].name) << "'abandon' requires one ingredient, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'abandon' requires one ingredient, but got '" << inst.to_string() << "'\n" << end();
     break;
   }
   reagent types = inst.ingredients.at(0);
   canonize_type(types);
-  if (!types.type || types.type->value != Type_ordinal["address"]) {
-    raise_error << maybe(Recipe[r].name) << "first ingredient of 'abandon' should be an address, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+  if (!types.type || types.type->value != get(Type_ordinal, "address")) {
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'abandon' should be an address, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -257,7 +257,7 @@ case ABANDON: {
   reagent types = current_instruction().ingredients.at(0);
   canonize(types);
   // lookup_memory without drop_one_lookup {
-  types.set_value(Memory[types.value]);
+  types.set_value(get_or_insert(Memory, types.value));
   drop_address_from_type(types);
   // }
   abandon(address, size_of(types));
@@ -271,26 +271,26 @@ void abandon(long long int address, long long int size) {
 //?   cerr << "abandon: " << size << '\n';
   // clear memory
   for (long long int curr = address; curr < address+size; ++curr)
-    Memory[curr] = 0;
+    put(Memory, curr, 0);
   // append existing free list to address
-  Memory[address] = Free_list[size];
+  put(Memory, address, Free_list[size]);
   Free_list[size] = address;
 }
 
 :(before "ensure_space(size)" following "case ALLOCATE")
 if (Free_list[size]) {
   long long int result = Free_list[size];
-  Free_list[size] = Memory[result];
+  Free_list[size] = get_or_insert(Memory, result);
   for (long long int curr = result+1; curr < result+size; ++curr) {
-    if (Memory[curr] != 0) {
+    if (get_or_insert(Memory, curr) != 0) {
       raise_error << maybe(current_recipe_name()) << "memory in free list was not zeroed out: " << curr << '/' << result << "; somebody wrote to us after free!!!\n" << end();
       break;  // always fatal
     }
   }
   if (SIZE(current_instruction().ingredients) > 1)
-    Memory[result] = ingredients.at(1).at(0);
+    put(Memory, result, ingredients.at(1).at(0));
   else
-    Memory[result] = 0;
+    put(Memory, result, 0);
   products.resize(1);
   products.at(0).push_back(result);
   break;
@@ -356,14 +356,14 @@ long long int new_mu_string(const string& contents) {
   ensure_space(string_length+1);  // don't forget the extra location for array size
   // initialize string
   long long int result = Current_routine->alloc;
-  Memory[Current_routine->alloc++] = string_length;
+  put(Memory, Current_routine->alloc++, string_length);
   long long int curr = 0;
   const char* raw_contents = contents.c_str();
   for (long long int i = 0; i < string_length; ++i) {
     uint32_t curr_character;
     assert(curr < SIZE(contents));
     tb_utf8_char_to_unicode(&curr_character, &raw_contents[curr]);
-    Memory[Current_routine->alloc] = curr_character;
+    put(Memory, Current_routine->alloc, curr_character);
     curr += tb_utf8_char_length(raw_contents[curr]);
     ++Current_routine->alloc;
   }
@@ -430,20 +430,20 @@ long long int unicode_length(const string& s) {
 
 bool is_mu_string(const reagent& x) {
   return x.type
-    && x.type->value == Type_ordinal["address"]
+    && x.type->value == get(Type_ordinal, "address")
     && x.type->right
-    && x.type->right->value == Type_ordinal["array"]
+    && x.type->right->value == get(Type_ordinal, "array")
     && x.type->right->right
-    && x.type->right->right->value == Type_ordinal["character"]
+    && x.type->right->right->value == get(Type_ordinal, "character")
     && x.type->right->right->right == NULL;
 }
 
 string read_mu_string(long long int address) {
-  long long int size = Memory[address];
+  long long int size = get_or_insert(Memory, address);
   if (size == 0) return "";
   ostringstream tmp;
   for (long long int curr = address+1; curr <= address+size; ++curr) {
-    tmp << to_unicode(static_cast<uint32_t>(Memory[curr]));
+    tmp << to_unicode(static_cast<uint32_t>(get_or_insert(Memory, curr)));
   }
   return tmp.str();
 }
diff --git a/044space.cc b/044space.cc
index dd579a4f..0031536d 100644
--- a/044space.cc
+++ b/044space.cc
@@ -127,7 +127,7 @@ if (curr.name == "new-default-space") {
 :(after "vector<double> read_memory(reagent x)")
   if (x.name == "number-of-locals") {
     vector<double> result;
-    result.push_back(Name[Recipe_ordinal[current_recipe_name()]][""]);
+    result.push_back(Name[get(Recipe_ordinal, current_recipe_name())][""]);
     if (result.back() == 0)
       raise_error << "no space allocated for default-space in recipe " << current_recipe_name() << "; are you using names?\n" << end();
     return result;
@@ -170,9 +170,9 @@ if (curr.name == "local-scope") {
 :(code)
 void try_reclaim_locals() {
   // only reclaim routines starting with 'local-scope'
-  const recipe_ordinal r = Recipe_ordinal[current_recipe_name()];
-  if (Recipe[r].steps.empty()) return;
-  const instruction& inst = Recipe[r].steps.at(0);
+  const recipe_ordinal r = get(Recipe_ordinal, current_recipe_name());
+  if (get(Recipe, r).steps.empty()) return;
+  const instruction& inst = get(Recipe, r).steps.at(0);
   if (inst.old_name != "local-scope") return;
   abandon(current_call().default_space,
           /*array length*/1+/*number-of-locals*/Name[r][""]);
@@ -199,9 +199,9 @@ long long int space_base(const reagent& x) {
 
 long long int address(long long int offset, long long int base) {
   if (base == 0) return offset;  // raw
-  if (offset >= static_cast<long long int>(Memory[base])) {
+  if (offset >= static_cast<long long int>(get_or_insert(Memory, base))) {
     // todo: test
-    raise_error << "location " << offset << " is out of bounds " << no_scientific(Memory[base]) << " at " << base << '\n' << end();
+    raise_error << "location " << offset << " is out of bounds " << no_scientific(get_or_insert(Memory, base)) << " at " << base << '\n' << end();
   }
   return base+1 + offset;
 }
@@ -210,11 +210,11 @@ long long int address(long long int offset, long long int base) {
   if (x.name == "default-space") {
     if (!scalar(data)
         || !x.type
-        || x.type->value != Type_ordinal["address"]
+        || x.type->value != get(Type_ordinal, "address")
         || !x.type->right
-        || x.type->right->value != Type_ordinal["array"]
+        || x.type->right->value != get(Type_ordinal, "array")
         || !x.type->right->right
-        || x.type->right->right->value != Type_ordinal["location"]
+        || x.type->right->right->value != get(Type_ordinal, "location")
         || x.type->right->right->right) {
       raise_error << maybe(current_recipe_name()) << "'default-space' should be of type address:array:location, but tried to write " << to_string(data) << '\n' << end();
     }
diff --git a/045space_surround.cc b/045space_surround.cc
index 880c350e..940f82b8 100644
--- a/045space_surround.cc
+++ b/045space_surround.cc
@@ -34,7 +34,7 @@ long long int space_base(const reagent& x, long long int space_index, long long
   if (space_index == 0) {
     return base;
   }
-  long long int result = space_base(x, space_index-1, Memory[base+1]);
+  long long int result = space_base(x, space_index-1, get_or_insert(Memory, base+1));
   return result;
 }
 
diff --git a/046closure_name.cc b/046closure_name.cc
index 56b3227a..70c3481e 100644
--- a/046closure_name.cc
+++ b/046closure_name.cc
@@ -40,38 +40,38 @@ Transform.push_back(collect_surrounding_spaces);
 
 :(code)
 void collect_surrounding_spaces(const recipe_ordinal r) {
-  trace(9991, "transform") << "--- collect surrounding spaces for recipe " << Recipe[r].name << end();
-  for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
-    const instruction& inst = Recipe[r].steps.at(i);
+  trace(9991, "transform") << "--- collect surrounding spaces for recipe " << get(Recipe, r).name << end();
+  for (long long int i = 0; i < SIZE(get(Recipe, r).steps); ++i) {
+    const instruction& inst = get(Recipe, r).steps.at(i);
     if (inst.is_label) continue;
     for (long long int j = 0; j < SIZE(inst.products); ++j) {
       if (is_literal(inst.products.at(j))) continue;
       if (inst.products.at(j).name != "0") continue;
       type_tree* type = inst.products.at(j).type;
       if (!type
-          || type->value != Type_ordinal["address"]
+          || type->value != get(Type_ordinal, "address")
           || !type->right
-          || type->right->value != Type_ordinal["array"]
+          || type->right->value != get(Type_ordinal, "array")
           || !type->right->right
-          || type->right->right->value != Type_ordinal["location"]
+          || type->right->right->value != get(Type_ordinal, "location")
           || type->right->right->right) {
         raise_error << "slot 0 should always have type address:array:location, but is " << inst.products.at(j).to_string() << '\n' << end();
         continue;
       }
       string_tree* s = property(inst.products.at(j), "names");
       if (!s) {
-        raise_error << "slot 0 requires a /names property in recipe " << Recipe[r].name << end();
+        raise_error << "slot 0 requires a /names property in recipe " << get(Recipe, r).name << end();
         continue;
       }
       if (s->right) raise_error << "slot 0 should have a single value in /names, but got " << inst.products.at(j).to_string() << '\n' << end();
       const string& surrounding_recipe_name = s->value;
       if (Surrounding_space.find(r) != Surrounding_space.end()
-          && Surrounding_space[r] != Recipe_ordinal[surrounding_recipe_name]) {
-        raise_error << "recipe " << Recipe[r].name << " can have only one 'surrounding' recipe but has " << Recipe[Surrounding_space[r]].name << " and " << surrounding_recipe_name << '\n' << end();
+          && Surrounding_space[r] != get(Recipe_ordinal, surrounding_recipe_name)) {
+        raise_error << "recipe " << get(Recipe, r).name << " can have only one 'surrounding' recipe but has " << Recipe[Surrounding_space[r]].name << " and " << surrounding_recipe_name << '\n' << end();
         continue;
       }
-      trace(9993, "name") << "lexically surrounding space for recipe " << Recipe[r].name << " comes from " << surrounding_recipe_name << end();
-      Surrounding_space[r] = Recipe_ordinal[surrounding_recipe_name];
+      trace(9993, "name") << "lexically surrounding space for recipe " << get(Recipe, r).name << " comes from " << surrounding_recipe_name << end();
+      Surrounding_space[r] = get(Recipe_ordinal, surrounding_recipe_name);
     }
   }
 }
@@ -117,7 +117,7 @@ long long int lookup_name(const reagent& x, const recipe_ordinal r, set<recipe_o
 recipe_ordinal lookup_surrounding_recipe(const recipe_ordinal r, long long int n) {
   if (n == 0) return r;
   if (Surrounding_space.find(r) == Surrounding_space.end()) {
-    raise_error << "don't know surrounding recipe of " << Recipe[r].name << '\n' << end();
+    raise_error << "don't know surrounding recipe of " << get(Recipe, r).name << '\n' << end();
     return 0;
   }
   assert(Surrounding_space[r]);
diff --git a/047global.cc b/047global.cc
index b080b90d..c0e09ce4 100644
--- a/047global.cc
+++ b/047global.cc
@@ -33,11 +33,11 @@ global_space = 0;
   if (x.name == "global-space") {
     if (!scalar(data)
         || !x.type
-        || x.type->value != Type_ordinal["address"]
+        || x.type->value != get(Type_ordinal, "address")
         || !x.type->right
-        || x.type->right->value != Type_ordinal["array"]
+        || x.type->right->value != get(Type_ordinal, "array")
         || !x.type->right->right
-        || x.type->right->right->value != Type_ordinal["location"]
+        || x.type->right->right->value != get(Type_ordinal, "location")
         || x.type->right->right->right) {
       raise_error << maybe(current_recipe_name()) << "'global-space' should be of type address:array:location, but tried to write " << to_string(data) << '\n' << end();
     }
diff --git a/048check_type_by_name.cc b/048check_type_by_name.cc
index 938cacd5..a3deba6c 100644
--- a/048check_type_by_name.cc
+++ b/048check_type_by_name.cc
@@ -19,11 +19,11 @@ Transform.push_back(check_types_by_name);
 
 :(code)
 void check_types_by_name(const recipe_ordinal r) {
-  trace(9991, "transform") << "--- deduce types for recipe " << Recipe[r].name << end();
+  trace(9991, "transform") << "--- deduce types for recipe " << get(Recipe, r).name << end();
   map<string, type_tree*> type;
   map<string, string_tree*> type_name;
-  for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
-    instruction& inst = Recipe[r].steps.at(i);
+  for (long long int i = 0; i < SIZE(get(Recipe, r).steps); ++i) {
+    instruction& inst = get(Recipe, r).steps.at(i);
     for (long long int in = 0; in < SIZE(inst.ingredients); ++in) {
       deduce_missing_type(type, type_name, inst.ingredients.at(in));
       check_type(type, type_name, inst.ingredients.at(in), r);
@@ -49,7 +49,7 @@ void check_type(map<string, type_tree*>& type, map<string, string_tree*>& type_n
     type_name[x.name] = x.properties.at(0).second;
   }
   if (!types_match(type[x.name], x.type))
-    raise_error << maybe(Recipe[r].name) << x.name << " used with multiple types\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << x.name << " used with multiple types\n" << end();
 }
 
 :(scenario transform_fills_in_missing_types)
diff --git a/050scenario.cc b/050scenario.cc
index 31398ab8..e60ee771 100644
--- a/050scenario.cc
+++ b/050scenario.cc
@@ -188,7 +188,7 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 RUN,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["run"] = RUN;
+put(Recipe_ordinal, "run", RUN);
 :(before "End Primitive Recipe Checks")
 case RUN: {
   break;
@@ -251,7 +251,7 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 MEMORY_SHOULD_CONTAIN,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["memory-should-contain"] = MEMORY_SHOULD_CONTAIN;
+put(Recipe_ordinal, "memory-should-contain", MEMORY_SHOULD_CONTAIN);
 :(before "End Primitive Recipe Checks")
 case MEMORY_SHOULD_CONTAIN: {
   break;
@@ -284,14 +284,14 @@ void check_memory(const string& s) {
     if (locations_checked.find(address) != locations_checked.end())
       raise_error << "duplicate expectation for location " << address << '\n' << end();
     trace(9999, "run") << "checking location " << address << end();
-    if (Memory[address] != value) {
+    if (get_or_insert(Memory, address) != value) {
       if (Current_scenario && !Scenario_testing_scenario) {
         // genuine test in a mu file
-        raise_error << "\nF - " << Current_scenario->name << ": expected location " << address << " to contain " << no_scientific(value) << " but saw " << no_scientific(Memory[address]) << '\n' << end();
+        raise_error << "\nF - " << Current_scenario->name << ": expected location " << address << " to contain " << no_scientific(value) << " but saw " << no_scientific(get_or_insert(Memory, address)) << '\n' << end();
       }
       else {
         // just testing scenario support
-        raise_error << "expected location " << address << " to contain " << no_scientific(value) << " but saw " << no_scientific(Memory[address]) << '\n' << end();
+        raise_error << "expected location " << address << " to contain " << no_scientific(value) << " but saw " << no_scientific(get_or_insert(Memory, address)) << '\n' << end();
       }
       if (!Scenario_testing_scenario) {
         Passed = false;
@@ -324,11 +324,11 @@ void check_type(const string& lhs, istream& in) {
 
 void check_string(long long int address, const string& literal) {
   trace(9999, "run") << "checking string length at " << address << end();
-  if (Memory[address] != SIZE(literal)) {
+  if (get_or_insert(Memory, address) != SIZE(literal)) {
     if (Current_scenario && !Scenario_testing_scenario)
-      raise_error << "\nF - " << Current_scenario->name << ": expected location " << address << " to contain length " << SIZE(literal) << " of string [" << literal << "] but saw " << no_scientific(Memory[address]) << '\n' << end();
+      raise_error << "\nF - " << Current_scenario->name << ": expected location " << address << " to contain length " << SIZE(literal) << " of string [" << literal << "] but saw " << no_scientific(get_or_insert(Memory, address)) << '\n' << end();
     else
-      raise_error << "expected location " << address << " to contain length " << SIZE(literal) << " of string [" << literal << "] but saw " << no_scientific(Memory[address]) << '\n' << end();
+      raise_error << "expected location " << address << " to contain length " << SIZE(literal) << " of string [" << literal << "] but saw " << no_scientific(get_or_insert(Memory, address)) << '\n' << end();
     if (!Scenario_testing_scenario) {
       Passed = false;
       ++Num_failures;
@@ -338,14 +338,14 @@ void check_string(long long int address, const string& literal) {
   ++address;  // now skip length
   for (long long int i = 0; i < SIZE(literal); ++i) {
     trace(9999, "run") << "checking location " << address+i << end();
-    if (Memory[address+i] != literal.at(i)) {
+    if (get_or_insert(Memory, address+i) != literal.at(i)) {
       if (Current_scenario && !Scenario_testing_scenario) {
         // genuine test in a mu file
-        raise_error << "\nF - " << Current_scenario->name << ": expected location " << (address+i) << " to contain " << literal.at(i) << " but saw " << no_scientific(Memory[address+i]) << '\n' << end();
+        raise_error << "\nF - " << Current_scenario->name << ": expected location " << (address+i) << " to contain " << literal.at(i) << " but saw " << no_scientific(get_or_insert(Memory, address+i)) << '\n' << end();
       }
       else {
         // just testing scenario support
-        raise_error << "expected location " << (address+i) << " to contain " << literal.at(i) << " but saw " << no_scientific(Memory[address+i]) << '\n' << end();
+        raise_error << "expected location " << (address+i) << " to contain " << literal.at(i) << " but saw " << no_scientific(get_or_insert(Memory, address+i)) << '\n' << end();
       }
       if (!Scenario_testing_scenario) {
         Passed = false;
@@ -416,7 +416,7 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 TRACE_SHOULD_CONTAIN,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["trace-should-contain"] = TRACE_SHOULD_CONTAIN;
+put(Recipe_ordinal, "trace-should-contain", TRACE_SHOULD_CONTAIN);
 :(before "End Primitive Recipe Checks")
 case TRACE_SHOULD_CONTAIN: {
   break;
@@ -512,7 +512,7 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 TRACE_SHOULD_NOT_CONTAIN,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["trace-should-not-contain"] = TRACE_SHOULD_NOT_CONTAIN;
+put(Recipe_ordinal, "trace-should-not-contain", TRACE_SHOULD_NOT_CONTAIN);
 :(before "End Primitive Recipe Checks")
 case TRACE_SHOULD_NOT_CONTAIN: {
   break;
@@ -576,19 +576,19 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 CHECK_TRACE_COUNT_FOR_LABEL,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["check-trace-count-for-label"] = CHECK_TRACE_COUNT_FOR_LABEL;
+put(Recipe_ordinal, "check-trace-count-for-label", CHECK_TRACE_COUNT_FOR_LABEL);
 :(before "End Primitive Recipe Checks")
 case CHECK_TRACE_COUNT_FOR_LABEL: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(Recipe[r].name) << "'check-trace-for-label' requires exactly two ingredients, but got '" << inst.to_string() << "'\n" << end();
+    raise_error << maybe(get(Recipe, r).name) << "'check-trace-for-label' requires exactly two ingredients, but got '" << inst.to_string() << "'\n" << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "first ingredient of 'check-trace-for-label' should be a number (count), but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'check-trace-for-label' should be a number (count), but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   if (!is_literal_string(inst.ingredients.at(1))) {
-    raise_error << maybe(Recipe[r].name) << "second ingredient of 'check-trace-for-label' should be a literal string (label), but got " << inst.ingredients.at(1).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "second ingredient of 'check-trace-for-label' should be a literal string (label), but got " << inst.ingredients.at(1).original_string << '\n' << end();
     break;
   }
   break;
diff --git a/052tangle.cc b/052tangle.cc
index 0582f79f..c3bc7e46 100644
--- a/052tangle.cc
+++ b/052tangle.cc
@@ -73,8 +73,8 @@ void insert_fragments(const recipe_ordinal r) {
     made_progress = false;
     // create a new vector because insertions invalidate iterators
     vector<instruction> result;
-    for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
-      const instruction& inst = Recipe[r].steps.at(i);
+    for (long long int i = 0; i < SIZE(get(Recipe, r).steps); ++i) {
+      const instruction& inst = get(Recipe, r).steps.at(i);
       if (!inst.is_label || !is_waypoint(inst.label) || inst.tangle_done) {
         result.push_back(inst);
         continue;
@@ -83,7 +83,7 @@ void insert_fragments(const recipe_ordinal r) {
       made_progress = true;
       Fragments_used.insert(inst.label);
       ostringstream prefix;
-      prefix << '+' << Recipe[r].name << '_' << pass << '_' << i;
+      prefix << '+' << get(Recipe, r).name << '_' << pass << '_' << i;
       if (Before_fragments.find(inst.label) != Before_fragments.end()) {
         append_fragment(result, Before_fragments[inst.label].steps, prefix.str());
       }
@@ -92,7 +92,7 @@ void insert_fragments(const recipe_ordinal r) {
         append_fragment(result, After_fragments[inst.label].steps, prefix.str());
       }
     }
-    Recipe[r].steps.swap(result);
+    get(Recipe, r).steps.swap(result);
     ++pass;
   }
 }
diff --git a/054dilated_reagent.cc b/054dilated_reagent.cc
index 46f5f8ab..5ac1c97e 100644
--- a/054dilated_reagent.cc
+++ b/054dilated_reagent.cc
@@ -86,9 +86,9 @@ if (s.at(0) == '{') {
   string type_name = properties.at(0).second->value;
   if (Type_ordinal.find(type_name) == Type_ordinal.end()) {
       // this type can't be an integer literal
-    Type_ordinal[type_name] = Next_type_ordinal++;
+    put(Type_ordinal, type_name, Next_type_ordinal++);
   }
-  type = new type_tree(Type_ordinal[type_name]);
+  type = new type_tree(get(Type_ordinal, type_name));
   return;
 }
 
diff --git a/056recipe_header.cc b/056recipe_header.cc
index bcea6328..cb63b013 100644
--- a/056recipe_header.cc
+++ b/056recipe_header.cc
@@ -80,7 +80,7 @@ if (result.has_header) {
 if (curr.name == "load-ingredients") {
   curr.clear();
   for (long long int i = 0; i < SIZE(result.ingredients); ++i) {
-    curr.operation = Recipe_ordinal["next-ingredient"];
+    curr.operation = get(Recipe_ordinal, "next-ingredient");
     curr.name = "next-ingredient";
     curr.products.push_back(result.ingredients.at(i));
     result.steps.push_back(curr);
@@ -106,7 +106,7 @@ Transform.push_back(check_header_products);
 
 :(code)
 void check_header_products(const recipe_ordinal r) {
-  const recipe& rr = Recipe[r];
+  const recipe& rr = get(Recipe, r);
   if (rr.products.empty()) return;
   trace(9991, "transform") << "--- checking reply instructions against header for " << rr.name << end();
   for (long long int i = 0; i < SIZE(rr.steps); ++i) {
@@ -143,7 +143,7 @@ Transform.push_back(deduce_types_from_header);
 
 :(code)
 void deduce_types_from_header(const recipe_ordinal r) {
-  recipe& rr = Recipe[r];
+  recipe& rr = get(Recipe, r);
   if (rr.products.empty()) return;
   trace(9991, "transform") << "--- deduce types from header for " << rr.name << end();
   map<string, const type_tree*> header;
@@ -197,13 +197,13 @@ Transform.push_back(fill_in_reply_ingredients);
 
 :(code)
 void fill_in_reply_ingredients(recipe_ordinal r) {
-  if (!Recipe[r].has_header) return;
-  trace(9991, "transform") << "--- fill in reply ingredients from header for recipe " << Recipe[r].name << end();
-  for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
-    instruction& inst = Recipe[r].steps.at(i);
+  if (!get(Recipe, r).has_header) return;
+  trace(9991, "transform") << "--- fill in reply ingredients from header for recipe " << get(Recipe, r).name << end();
+  for (long long int i = 0; i < SIZE(get(Recipe, r).steps); ++i) {
+    instruction& inst = get(Recipe, r).steps.at(i);
     if (inst.name == "reply" && inst.ingredients.empty()) {
-      for (long long int i = 0; i < SIZE(Recipe[r].products); ++i)
-        inst.ingredients.push_back(Recipe[r].products.at(i));
+      for (long long int i = 0; i < SIZE(get(Recipe, r).products); ++i)
+        inst.ingredients.push_back(get(Recipe, r).products.at(i));
     }
   }
 }
@@ -239,7 +239,7 @@ Transform.push_back(deduce_fallthrough_reply);
 
 :(code)
 void deduce_fallthrough_reply(const recipe_ordinal r) {
-  recipe& rr = Recipe[r];
+  recipe& rr = get(Recipe, r);
   if (rr.products.empty()) return;
   if (rr.steps.empty()) return;
   if (rr.steps.at(SIZE(rr.steps)-1).name != "reply") {
diff --git a/057static_dispatch.cc b/057static_dispatch.cc
index 3bac046e..905cbaf2 100644
--- a/057static_dispatch.cc
+++ b/057static_dispatch.cc
@@ -29,19 +29,19 @@ for (map<string, vector<recipe_ordinal> >::iterator p = Recipe_variants.begin();
 
 :(before "End Load Recipe Header(result)")
 if (Recipe_ordinal.find(result.name) != Recipe_ordinal.end()) {
-  if ((Recipe.find(Recipe_ordinal[result.name]) == Recipe.end()
-          || Recipe[Recipe_ordinal[result.name]].has_header)
+  if ((Recipe.find(get(Recipe_ordinal, result.name)) == Recipe.end()
+          || get(Recipe, get(Recipe_ordinal, result.name)).has_header)
       && !header_already_exists(result)) {
     string new_name = next_unused_recipe_name(result.name);
-    Recipe_ordinal[new_name] = Next_recipe_ordinal++;
-    Recipe_variants[result.name].push_back(Recipe_ordinal[new_name]);
+    put(Recipe_ordinal, new_name, Next_recipe_ordinal++);
+    Recipe_variants[result.name].push_back(get(Recipe_ordinal, new_name));
     result.name = new_name;
   }
 }
 else {
   // save first variant
-  Recipe_ordinal[result.name] = Next_recipe_ordinal++;
-  Recipe_variants[result.name].push_back(Recipe_ordinal[result.name]);
+  put(Recipe_ordinal, result.name, Next_recipe_ordinal++);
+  Recipe_variants[result.name].push_back(get(Recipe_ordinal, result.name));
 }
 
 :(code)
@@ -49,7 +49,7 @@ bool header_already_exists(const recipe& rr) {
   const vector<recipe_ordinal>& variants = Recipe_variants[rr.name];
   for (long long int i = 0; i < SIZE(variants); ++i) {
     if (Recipe.find(variants.at(i)) != Recipe.end()
-        && all_reagents_match(rr, Recipe[variants.at(i)])) {
+        && all_reagents_match(rr, get(Recipe, variants.at(i)))) {
       return true;
     }
   }
@@ -108,10 +108,10 @@ Transform.push_back(resolve_ambiguous_calls);
 
 :(code)
 void resolve_ambiguous_calls(recipe_ordinal r) {
-  if (!Recipe[r].has_header) return;
-  trace(9991, "transform") << "--- resolve ambiguous calls for recipe " << Recipe[r].name << end();
-  for (long long int index = 0; index < SIZE(Recipe[r].steps); ++index) {
-    instruction& inst = Recipe[r].steps.at(index);
+  if (!get(Recipe, r).has_header) return;
+  trace(9991, "transform") << "--- resolve ambiguous calls for recipe " << get(Recipe, r).name << end();
+  for (long long int index = 0; index < SIZE(get(Recipe, r).steps); ++index) {
+    instruction& inst = get(Recipe, r).steps.at(index);
     if (inst.is_label) continue;
     if (Recipe_variants.find(inst.name) == Recipe_variants.end()) continue;
     assert(!Recipe_variants[inst.name].empty());
@@ -122,12 +122,12 @@ void resolve_ambiguous_calls(recipe_ordinal r) {
 void replace_best_variant(instruction& inst) {
   trace(9992, "transform") << "instruction " << inst.name << end();
   vector<recipe_ordinal>& variants = Recipe_variants[inst.name];
-  long long int best_score = variant_score(inst, Recipe_ordinal[inst.name]);
+  long long int best_score = variant_score(inst, get(Recipe_ordinal, inst.name));
   for (long long int i = 0; i < SIZE(variants); ++i) {
     long long int current_score = variant_score(inst, variants.at(i));
     trace(9992, "transform") << "checking variant " << i << ": " << current_score << end();
     if (current_score > best_score) {
-      inst.name = Recipe[variants.at(i)].name;
+      inst.name = get(Recipe, variants.at(i)).name;
       best_score = current_score;
     }
   }
@@ -136,7 +136,7 @@ void replace_best_variant(instruction& inst) {
 
 long long int variant_score(const instruction& inst, recipe_ordinal variant) {
   if (variant == -1) return -1;
-  const vector<reagent>& header_ingredients = Recipe[variant].ingredients;
+  const vector<reagent>& header_ingredients = get(Recipe, variant).ingredients;
   if (SIZE(inst.ingredients) < SIZE(header_ingredients)) {
     trace(9993, "transform") << "too few ingredients" << end();
     return -1;
@@ -147,11 +147,11 @@ long long int variant_score(const instruction& inst, recipe_ordinal variant) {
       return -1;
     }
   }
-  if (SIZE(inst.products) > SIZE(Recipe[variant].products)) {
+  if (SIZE(inst.products) > SIZE(get(Recipe, variant).products)) {
     trace(9993, "transform") << "too few products" << end();
     return -1;
   }
-  const vector<reagent>& header_products = Recipe[variant].products;
+  const vector<reagent>& header_products = get(Recipe, variant).products;
   for (long long int i = 0; i < SIZE(inst.products); ++i) {
     if (!types_match(header_products.at(i), inst.products.at(i))) {
       trace(9993, "transform") << "mismatch: product " << i << end();
@@ -159,8 +159,8 @@ long long int variant_score(const instruction& inst, recipe_ordinal variant) {
     }
   }
   // the greater the number of unused ingredients, the lower the score
-  return 100 - (SIZE(Recipe[variant].products)-SIZE(inst.products))
-             - (SIZE(inst.ingredients)-SIZE(Recipe[variant].ingredients));  // ok to go negative
+  return 100 - (SIZE(get(Recipe, variant).products)-SIZE(inst.products))
+             - (SIZE(inst.ingredients)-SIZE(get(Recipe, variant).ingredients));  // ok to go negative
 }
 
 :(scenario static_dispatch_disabled_on_headerless_definition)
diff --git a/058generic_container.cc b/058generic_container.cc
index e757143b..6ba05d5e 100644
--- a/058generic_container.cc
+++ b/058generic_container.cc
@@ -50,9 +50,9 @@ void read_type_ingredients(string& name) {
   string save_name = name;
   istringstream in(save_name);
   name = slurp_until(in, ':');
-  if (Type_ordinal.find(name) == Type_ordinal.end() || Type_ordinal[name] == 0)
-    Type_ordinal[name] = Next_type_ordinal++;
-  type_info& info = Type[Type_ordinal[name]];
+  if (Type_ordinal.find(name) == Type_ordinal.end() || get(Type_ordinal, name) == 0)
+    put(Type_ordinal, name, Next_type_ordinal++);
+  type_info& info = get(Type, get(Type_ordinal, name));
   long long int next_type_ordinal = START_TYPE_INGREDIENTS;
   while (!in.eof()) {
     string curr = slurp_until(in, ':');
@@ -74,7 +74,7 @@ if (type_name.at(0) == '_') {
 
 :(before "End Container Type Checks")
 if (type->value >= START_TYPE_INGREDIENTS
-    && (type->value - START_TYPE_INGREDIENTS) < SIZE(Type[type->value].type_ingredient_names))
+    && (type->value - START_TYPE_INGREDIENTS) < SIZE(get(Type, type->value).type_ingredient_names))
   return;
 
 :(before "End size_of(type) Container Cases")
@@ -103,7 +103,7 @@ long long int size_of_type_ingredient(const type_tree* element_template, const t
   }
   assert(curr);
   assert(!curr->left);  // unimplemented
-  trace(9999, "type") << "type deduced to be " << Type[curr->value].name << "$" << end();
+  trace(9999, "type") << "type deduced to be " << get(Type, curr->value).name << "$" << end();
   type_tree tmp(curr->value);
   if (curr->right)
     tmp.right = new type_tree(*curr->right);
@@ -122,8 +122,8 @@ recipe main [
 +mem: storing 16 in location 2
 
 :(before "End GET field Cases")
-if (Type[base_type].elements.at(i)->value >= START_TYPE_INGREDIENTS) {
-  src += size_of_type_ingredient(Type[base_type].elements.at(i), base.type->right);
+if (get(Type, base_type).elements.at(i)->value >= START_TYPE_INGREDIENTS) {
+  src += size_of_type_ingredient(get(Type, base_type).elements.at(i), base.type->right);
   continue;
 }
 
@@ -212,8 +212,8 @@ recipe main [
 +mem: storing 12 in location 1
 
 :(before "End GET_ADDRESS field Cases")
-if (Type[base_type].elements.at(i)->value >= START_TYPE_INGREDIENTS) {
-  result += size_of_type_ingredient(Type[base_type].elements.at(i), base.type->right);
+if (get(Type, base_type).elements.at(i)->value >= START_TYPE_INGREDIENTS) {
+  result += size_of_type_ingredient(get(Type, base_type).elements.at(i), base.type->right);
   continue;
 }
 
diff --git a/059generic_recipe.cc b/059generic_recipe.cc
index 2fe08c27..106d5a14 100644
--- a/059generic_recipe.cc
+++ b/059generic_recipe.cc
@@ -31,9 +31,9 @@ if (best_score == -1) {
   trace(9992, "transform") << "no variant found; searching for variant with suitable type ingredients" << end();
   recipe_ordinal exemplar = pick_matching_generic_variant(variants, inst, best_score);
   if (exemplar) {
-    trace(9992, "transform") << "found variant to specialize: " << exemplar << ' ' << Recipe[exemplar].name << end();
+    trace(9992, "transform") << "found variant to specialize: " << exemplar << ' ' << get(Recipe, exemplar).name << end();
     variants.push_back(new_variant(exemplar, inst));
-    inst.name = Recipe[variants.back()].name;
+    inst.name = get(Recipe, variants.back()).name;
     trace(9992, "transform") << "new specialization: " << inst.name << end();
   }
 }
@@ -65,7 +65,7 @@ long long int generic_variant_score(const instruction& inst, recipe_ordinal vari
     trace(9993, "transform") << "no type ingredients" << end();
     return -1;
   }
-  const vector<reagent>& header_ingredients = Recipe[variant].ingredients;
+  const vector<reagent>& header_ingredients = get(Recipe, variant).ingredients;
   if (SIZE(inst.ingredients) < SIZE(header_ingredients)) {
     trace(9993, "transform") << "too few ingredients" << end();
     return -1;
@@ -76,11 +76,11 @@ long long int generic_variant_score(const instruction& inst, recipe_ordinal vari
       return -1;
     }
   }
-  if (SIZE(inst.products) > SIZE(Recipe[variant].products)) {
+  if (SIZE(inst.products) > SIZE(get(Recipe, variant).products)) {
     trace(9993, "transform") << "too few products" << end();
     return -1;
   }
-  const vector<reagent>& header_products = Recipe[variant].products;
+  const vector<reagent>& header_products = get(Recipe, variant).products;
   for (long long int i = 0; i < SIZE(inst.products); ++i) {
     if (!non_type_ingredients_match(header_products.at(i), inst.products.at(i))) {
       trace(9993, "transform") << "mismatch: product " << i << end();
@@ -88,13 +88,13 @@ long long int generic_variant_score(const instruction& inst, recipe_ordinal vari
     }
   }
   // the greater the number of unused ingredients, the lower the score
-  return 100 - (SIZE(Recipe[variant].products)-SIZE(inst.products))
-             - (SIZE(inst.ingredients)-SIZE(Recipe[variant].ingredients));  // ok to go negative
+  return 100 - (SIZE(get(Recipe, variant).products)-SIZE(inst.products))
+             - (SIZE(inst.ingredients)-SIZE(get(Recipe, variant).ingredients));  // ok to go negative
 }
 
 bool any_type_ingredient_in_header(recipe_ordinal variant) {
-  for (long long int i = 0; i < SIZE(Recipe[variant].ingredients); ++i) {
-    if (contains_type_ingredient_name(Recipe[variant].ingredients.at(i)))
+  for (long long int i = 0; i < SIZE(get(Recipe, variant).ingredients); ++i) {
+    if (contains_type_ingredient_name(get(Recipe, variant).ingredients.at(i)))
       return true;
   }
   return false;
@@ -123,18 +123,18 @@ recipe_ordinal new_variant(recipe_ordinal exemplar, const instruction& inst) {
   string new_name = next_unused_recipe_name(inst.name);
   trace(9993, "transform") << "switching " << inst.name << " to " << new_name << end();
   assert(Recipe_ordinal.find(new_name) == Recipe_ordinal.end());
-  recipe_ordinal result = Recipe_ordinal[new_name] = Next_recipe_ordinal++;
+  recipe_ordinal result = put(Recipe_ordinal, new_name, Next_recipe_ordinal++);
   // make a copy
   assert(Recipe.find(exemplar) != Recipe.end());
   assert(Recipe.find(result) == Recipe.end());
   recently_added_recipes.push_back(result);
-  Recipe[result] = Recipe[exemplar];
-  recipe& new_recipe = Recipe[result];
+  put(Recipe, result, get(Recipe, exemplar));
+  recipe& new_recipe = get(Recipe, result);
   // update its name
   new_recipe.name = new_name;
   // update its contents
   map<string, string> mappings;  // weak references
-  compute_type_ingredient_mappings(Recipe[exemplar], inst, mappings);
+  compute_type_ingredient_mappings(get(Recipe, exemplar), inst, mappings);
   replace_type_ingredients(new_recipe, mappings);
   return result;
 }
diff --git a/064random.cc b/064random.cc
index 12e1b848..69ed8b2c 100644
--- a/064random.cc
+++ b/064random.cc
@@ -1,7 +1,7 @@
 :(before "End Primitive Recipe Declarations")
 RANDOM,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["random"] = RANDOM;
+put(Recipe_ordinal, "random", RANDOM);
 :(before "End Primitive Recipe Checks")
 case RANDOM: {
   break;
@@ -18,7 +18,7 @@ case RANDOM: {
 :(before "End Primitive Recipe Declarations")
 MAKE_RANDOM_NONDETERMINISTIC,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["make-random-nondeterministic"] = MAKE_RANDOM_NONDETERMINISTIC;
+put(Recipe_ordinal, "make-random-nondeterministic", MAKE_RANDOM_NONDETERMINISTIC);
 :(before "End Primitive Recipe Checks")
 case MAKE_RANDOM_NONDETERMINISTIC: {
   break;
@@ -32,15 +32,15 @@ case MAKE_RANDOM_NONDETERMINISTIC: {
 :(before "End Primitive Recipe Declarations")
 ROUND,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["round"] = ROUND;
+put(Recipe_ordinal, "round", ROUND);
 :(before "End Primitive Recipe Checks")
 case ROUND: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(Recipe[r].name) << "'round' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'round' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "first ingredient of 'round' should be a number, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'round' should be a number, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   break;
diff --git a/070display.cc b/070display.cc
index 49668a99..970887bd 100644
--- a/070display.cc
+++ b/070display.cc
@@ -9,7 +9,7 @@ bool Autodisplay = true;
 :(before "End Primitive Recipe Declarations")
 OPEN_CONSOLE,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["open-console"] = OPEN_CONSOLE;
+put(Recipe_ordinal, "open-console", OPEN_CONSOLE);
 :(before "End Primitive Recipe Checks")
 case OPEN_CONSOLE: {
   break;
@@ -31,7 +31,7 @@ case OPEN_CONSOLE: {
 :(before "End Primitive Recipe Declarations")
 CLOSE_CONSOLE,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["close-console"] = CLOSE_CONSOLE;
+put(Recipe_ordinal, "close-console", CLOSE_CONSOLE);
 :(before "End Primitive Recipe Checks")
 case CLOSE_CONSOLE: {
   break;
@@ -48,7 +48,7 @@ tb_shutdown();
 :(before "End Primitive Recipe Declarations")
 CLEAR_DISPLAY,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["clear-display"] = CLEAR_DISPLAY;
+put(Recipe_ordinal, "clear-display", CLEAR_DISPLAY);
 :(before "End Primitive Recipe Checks")
 case CLEAR_DISPLAY: {
   break;
@@ -63,7 +63,7 @@ case CLEAR_DISPLAY: {
 :(before "End Primitive Recipe Declarations")
 SYNC_DISPLAY,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["sync-display"] = SYNC_DISPLAY;
+put(Recipe_ordinal, "sync-display", SYNC_DISPLAY);
 :(before "End Primitive Recipe Checks")
 case SYNC_DISPLAY: {
   break;
@@ -77,7 +77,7 @@ case SYNC_DISPLAY: {
 :(before "End Primitive Recipe Declarations")
 CLEAR_LINE_ON_DISPLAY,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["clear-line-on-display"] = CLEAR_LINE_ON_DISPLAY;
+put(Recipe_ordinal, "clear-line-on-display", CLEAR_LINE_ON_DISPLAY);
 :(before "End Primitive Recipe Checks")
 case CLEAR_LINE_ON_DISPLAY: {
   break;
@@ -96,26 +96,26 @@ case CLEAR_LINE_ON_DISPLAY: {
 :(before "End Primitive Recipe Declarations")
 PRINT_CHARACTER_TO_DISPLAY,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["print-character-to-display"] = PRINT_CHARACTER_TO_DISPLAY;
+put(Recipe_ordinal, "print-character-to-display", PRINT_CHARACTER_TO_DISPLAY);
 :(before "End Primitive Recipe Checks")
 case PRINT_CHARACTER_TO_DISPLAY: {
   if (inst.ingredients.empty()) {
-    raise_error << maybe(Recipe[r].name) << "'print-character-to-display' requires at least one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'print-character-to-display' requires at least one ingredient, but got " << inst.to_string() << '\n' << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "first ingredient of 'print-character-to-display' should be a character, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'print-character-to-display' should be a character, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   if (SIZE(inst.ingredients) > 1) {
     if (!is_mu_number(inst.ingredients.at(1))) {
-      raise_error << maybe(Recipe[r].name) << "second ingredient of 'print-character-to-display' should be a foreground color number, but got " << inst.ingredients.at(1).original_string << '\n' << end();
+      raise_error << maybe(get(Recipe, r).name) << "second ingredient of 'print-character-to-display' should be a foreground color number, but got " << inst.ingredients.at(1).original_string << '\n' << end();
       break;
     }
   }
   if (SIZE(inst.ingredients) > 2) {
     if (!is_mu_number(inst.ingredients.at(2))) {
-      raise_error << maybe(Recipe[r].name) << "third ingredient of 'print-character-to-display' should be a background color number, but got " << inst.ingredients.at(2).original_string << '\n' << end();
+      raise_error << maybe(get(Recipe, r).name) << "third ingredient of 'print-character-to-display' should be a background color number, but got " << inst.ingredients.at(2).original_string << '\n' << end();
       break;
     }
   }
@@ -166,7 +166,7 @@ case PRINT_CHARACTER_TO_DISPLAY: {
 :(before "End Primitive Recipe Declarations")
 CURSOR_POSITION_ON_DISPLAY,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["cursor-position-on-display"] = CURSOR_POSITION_ON_DISPLAY;
+put(Recipe_ordinal, "cursor-position-on-display", CURSOR_POSITION_ON_DISPLAY);
 :(before "End Primitive Recipe Checks")
 case CURSOR_POSITION_ON_DISPLAY: {
   break;
@@ -182,19 +182,19 @@ case CURSOR_POSITION_ON_DISPLAY: {
 :(before "End Primitive Recipe Declarations")
 MOVE_CURSOR_ON_DISPLAY,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["move-cursor-on-display"] = MOVE_CURSOR_ON_DISPLAY;
+put(Recipe_ordinal, "move-cursor-on-display", MOVE_CURSOR_ON_DISPLAY);
 :(before "End Primitive Recipe Checks")
 case MOVE_CURSOR_ON_DISPLAY: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(Recipe[r].name) << "'move-cursor-on-display' requires two ingredients, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'move-cursor-on-display' requires two ingredients, but got " << inst.to_string() << '\n' << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "first ingredient of 'move-cursor-on-display' should be a row number, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'move-cursor-on-display' should be a row number, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   if (!is_mu_number(inst.ingredients.at(1))) {
-    raise_error << maybe(Recipe[r].name) << "second ingredient of 'move-cursor-on-display' should be a column number, but got " << inst.ingredients.at(1).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "second ingredient of 'move-cursor-on-display' should be a column number, but got " << inst.ingredients.at(1).original_string << '\n' << end();
     break;
   }
   break;
@@ -211,7 +211,7 @@ case MOVE_CURSOR_ON_DISPLAY: {
 :(before "End Primitive Recipe Declarations")
 MOVE_CURSOR_DOWN_ON_DISPLAY,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["move-cursor-down-on-display"] = MOVE_CURSOR_DOWN_ON_DISPLAY;
+put(Recipe_ordinal, "move-cursor-down-on-display", MOVE_CURSOR_DOWN_ON_DISPLAY);
 :(before "End Primitive Recipe Checks")
 case MOVE_CURSOR_DOWN_ON_DISPLAY: {
   break;
@@ -231,7 +231,7 @@ case MOVE_CURSOR_DOWN_ON_DISPLAY: {
 :(before "End Primitive Recipe Declarations")
 MOVE_CURSOR_UP_ON_DISPLAY,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["move-cursor-up-on-display"] = MOVE_CURSOR_UP_ON_DISPLAY;
+put(Recipe_ordinal, "move-cursor-up-on-display", MOVE_CURSOR_UP_ON_DISPLAY);
 :(before "End Primitive Recipe Checks")
 case MOVE_CURSOR_UP_ON_DISPLAY: {
   break;
@@ -249,7 +249,7 @@ case MOVE_CURSOR_UP_ON_DISPLAY: {
 :(before "End Primitive Recipe Declarations")
 MOVE_CURSOR_RIGHT_ON_DISPLAY,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["move-cursor-right-on-display"] = MOVE_CURSOR_RIGHT_ON_DISPLAY;
+put(Recipe_ordinal, "move-cursor-right-on-display", MOVE_CURSOR_RIGHT_ON_DISPLAY);
 :(before "End Primitive Recipe Checks")
 case MOVE_CURSOR_RIGHT_ON_DISPLAY: {
   break;
@@ -269,7 +269,7 @@ case MOVE_CURSOR_RIGHT_ON_DISPLAY: {
 :(before "End Primitive Recipe Declarations")
 MOVE_CURSOR_LEFT_ON_DISPLAY,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["move-cursor-left-on-display"] = MOVE_CURSOR_LEFT_ON_DISPLAY;
+put(Recipe_ordinal, "move-cursor-left-on-display", MOVE_CURSOR_LEFT_ON_DISPLAY);
 :(before "End Primitive Recipe Checks")
 case MOVE_CURSOR_LEFT_ON_DISPLAY: {
   break;
@@ -287,7 +287,7 @@ case MOVE_CURSOR_LEFT_ON_DISPLAY: {
 :(before "End Primitive Recipe Declarations")
 DISPLAY_WIDTH,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["display-width"] = DISPLAY_WIDTH;
+put(Recipe_ordinal, "display-width", DISPLAY_WIDTH);
 :(before "End Primitive Recipe Checks")
 case DISPLAY_WIDTH: {
   break;
@@ -302,7 +302,7 @@ case DISPLAY_WIDTH: {
 :(before "End Primitive Recipe Declarations")
 DISPLAY_HEIGHT,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["display-height"] = DISPLAY_HEIGHT;
+put(Recipe_ordinal, "display-height", DISPLAY_HEIGHT);
 :(before "End Primitive Recipe Checks")
 case DISPLAY_HEIGHT: {
   break;
@@ -317,7 +317,7 @@ case DISPLAY_HEIGHT: {
 :(before "End Primitive Recipe Declarations")
 HIDE_CURSOR_ON_DISPLAY,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["hide-cursor-on-display"] = HIDE_CURSOR_ON_DISPLAY;
+put(Recipe_ordinal, "hide-cursor-on-display", HIDE_CURSOR_ON_DISPLAY);
 :(before "End Primitive Recipe Checks")
 case HIDE_CURSOR_ON_DISPLAY: {
   break;
@@ -331,7 +331,7 @@ case HIDE_CURSOR_ON_DISPLAY: {
 :(before "End Primitive Recipe Declarations")
 SHOW_CURSOR_ON_DISPLAY,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["show-cursor-on-display"] = SHOW_CURSOR_ON_DISPLAY;
+put(Recipe_ordinal, "show-cursor-on-display", SHOW_CURSOR_ON_DISPLAY);
 :(before "End Primitive Recipe Checks")
 case SHOW_CURSOR_ON_DISPLAY: {
   break;
@@ -345,7 +345,7 @@ case SHOW_CURSOR_ON_DISPLAY: {
 :(before "End Primitive Recipe Declarations")
 HIDE_DISPLAY,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["hide-display"] = HIDE_DISPLAY;
+put(Recipe_ordinal, "hide-display", HIDE_DISPLAY);
 :(before "End Primitive Recipe Checks")
 case HIDE_DISPLAY: {
   break;
@@ -359,7 +359,7 @@ case HIDE_DISPLAY: {
 :(before "End Primitive Recipe Declarations")
 SHOW_DISPLAY,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["show-display"] = SHOW_DISPLAY;
+put(Recipe_ordinal, "show-display", SHOW_DISPLAY);
 :(before "End Primitive Recipe Checks")
 case SHOW_DISPLAY: {
   break;
@@ -376,7 +376,7 @@ case SHOW_DISPLAY: {
 :(before "End Primitive Recipe Declarations")
 WAIT_FOR_SOME_INTERACTION,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["wait-for-some-interaction"] = WAIT_FOR_SOME_INTERACTION;
+put(Recipe_ordinal, "wait-for-some-interaction", WAIT_FOR_SOME_INTERACTION);
 :(before "End Primitive Recipe Checks")
 case WAIT_FOR_SOME_INTERACTION: {
   break;
@@ -391,7 +391,7 @@ case WAIT_FOR_SOME_INTERACTION: {
 :(before "End Primitive Recipe Declarations")
 CHECK_FOR_INTERACTION,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["check-for-interaction"] = CHECK_FOR_INTERACTION;
+put(Recipe_ordinal, "check-for-interaction", CHECK_FOR_INTERACTION);
 :(before "End Primitive Recipe Checks")
 case CHECK_FOR_INTERACTION: {
   break;
@@ -458,7 +458,7 @@ case CHECK_FOR_INTERACTION: {
 :(before "End Primitive Recipe Declarations")
 INTERACTIONS_LEFT,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["interactions-left?"] = INTERACTIONS_LEFT;
+put(Recipe_ordinal, "interactions-left?", INTERACTIONS_LEFT);
 :(before "End Primitive Recipe Checks")
 case INTERACTIONS_LEFT: {
   break;
@@ -475,7 +475,7 @@ case INTERACTIONS_LEFT: {
 :(before "End Primitive Recipe Declarations")
 CLEAR_DISPLAY_FROM,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["clear-display-from"] = CLEAR_DISPLAY_FROM;
+put(Recipe_ordinal, "clear-display-from", CLEAR_DISPLAY_FROM);
 :(before "End Primitive Recipe Checks")
 case CLEAR_DISPLAY_FROM: {
   break;
diff --git a/072scenario_screen.cc b/072scenario_screen.cc
index 97002005..a82862c0 100644
--- a/072scenario_screen.cc
+++ b/072scenario_screen.cc
@@ -151,7 +151,7 @@ if (curr.name == "assume-screen") {
 :(before "End Primitive Recipe Declarations")
 SCREEN_SHOULD_CONTAIN,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["screen-should-contain"] = SCREEN_SHOULD_CONTAIN;
+put(Recipe_ordinal, "screen-should-contain", SCREEN_SHOULD_CONTAIN);
 :(before "End Primitive Recipe Checks")
 case SCREEN_SHOULD_CONTAIN: {
   break;
@@ -166,7 +166,7 @@ case SCREEN_SHOULD_CONTAIN: {
 :(before "End Primitive Recipe Declarations")
 SCREEN_SHOULD_CONTAIN_IN_COLOR,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["screen-should-contain-in-color"] = SCREEN_SHOULD_CONTAIN_IN_COLOR;
+put(Recipe_ordinal, "screen-should-contain-in-color", SCREEN_SHOULD_CONTAIN_IN_COLOR);
 :(before "End Primitive Recipe Checks")
 case SCREEN_SHOULD_CONTAIN_IN_COLOR: {
   break;
@@ -196,15 +196,15 @@ struct raw_string_stream {
 :(code)
 void check_screen(const string& expected_contents, const int color) {
   assert(!current_call().default_space);  // not supported
-  long long int screen_location = Memory[SCREEN];
-  int data_offset = find_element_name(Type_ordinal["screen"], "data", "");
+  long long int screen_location = get_or_insert(Memory, SCREEN);
+  int data_offset = find_element_name(get(Type_ordinal, "screen"), "data", "");
   assert(data_offset >= 0);
   long long int screen_data_location = screen_location+data_offset;  // type: address:array:character
-  long long int screen_data_start = Memory[screen_data_location];  // type: array:character
-  int width_offset = find_element_name(Type_ordinal["screen"], "num-columns", "");
-  long long int screen_width = Memory[screen_location+width_offset];
-  int height_offset = find_element_name(Type_ordinal["screen"], "num-rows", "");
-  long long int screen_height = Memory[screen_location+height_offset];
+  long long int screen_data_start = get_or_insert(Memory, screen_data_location);  // type: array:character
+  int width_offset = find_element_name(get(Type_ordinal, "screen"), "num-columns", "");
+  long long int screen_width = get_or_insert(Memory, screen_location+width_offset);
+  int height_offset = find_element_name(get(Type_ordinal, "screen"), "num-rows", "");
+  long long int screen_height = get_or_insert(Memory, screen_location+height_offset);
   raw_string_stream cursor(expected_contents);
   // todo: too-long expected_contents should fail
   long long int addr = screen_data_start+1;  // skip length
@@ -215,21 +215,21 @@ void check_screen(const string& expected_contents, const int color) {
     for (long long int column = 0;  column < screen_width;  ++column, addr+= /*size of screen-cell*/2) {
       const int cell_color_offset = 1;
       uint32_t curr = cursor.get();
-      if (Memory[addr] == 0 && isspace(curr)) continue;
-      if (curr == ' ' && color != -1 && color != Memory[addr+cell_color_offset]) {
+      if (get_or_insert(Memory, addr) == 0 && isspace(curr)) continue;
+      if (curr == ' ' && color != -1 && color != get_or_insert(Memory, addr+cell_color_offset)) {
         // filter out other colors
         continue;
       }
-      if (Memory[addr] != 0 && Memory[addr] == curr) {
-        if (color == -1 || color == Memory[addr+cell_color_offset]) continue;
+      if (get_or_insert(Memory, addr) != 0 && Memory[addr] == curr) {
+        if (color == -1 || color == get_or_insert(Memory, addr+cell_color_offset)) continue;
         // contents match but color is off
         if (Current_scenario && !Scenario_testing_scenario) {
           // genuine test in a mu file
-          raise_error << "\nF - " << Current_scenario->name << ": expected screen location (" << row << ", " << column << ", address " << addr << ", value " << no_scientific(Memory[addr]) << ") to be in color " << color << " instead of " << no_scientific(Memory[addr+cell_color_offset]) << "\n" << end();
+          raise_error << "\nF - " << Current_scenario->name << ": expected screen location (" << row << ", " << column << ", address " << addr << ", value " << no_scientific(get_or_insert(Memory, addr)) << ") to be in color " << color << " instead of " << no_scientific(Memory[addr+cell_color_offset]) << "\n" << end();
         }
         else {
           // just testing check_screen
-          raise_error << "expected screen location (" << row << ", " << column << ") to be in color " << color << " instead of " << no_scientific(Memory[addr+cell_color_offset]) << '\n' << end();
+          raise_error << "expected screen location (" << row << ", " << column << ") to be in color " << color << " instead of " << no_scientific(get_or_insert(Memory, addr+cell_color_offset)) << '\n' << end();
         }
         if (!Scenario_testing_scenario) {
           Passed = false;
@@ -246,21 +246,21 @@ void check_screen(const string& expected_contents, const int color) {
         expected_pretty[0] = ' ', expected_pretty[1] = '(', expected_pretty[2] = '\'', expected_pretty[3] = static_cast<unsigned char>(curr), expected_pretty[4] = '\'', expected_pretty[5] = ')', expected_pretty[6] = '\0';
       }
       char actual_pretty[10] = {0};
-      if (Memory[addr] < 256 && !iscntrl(Memory[addr])) {
+      if (get_or_insert(Memory, addr) < 256 && !iscntrl(Memory[addr])) {
         // " ('<curr>')"
-        actual_pretty[0] = ' ', actual_pretty[1] = '(', actual_pretty[2] = '\'', actual_pretty[3] = static_cast<unsigned char>(Memory[addr]), actual_pretty[4] = '\'', actual_pretty[5] = ')', actual_pretty[6] = '\0';
+        actual_pretty[0] = ' ', actual_pretty[1] = '(', actual_pretty[2] = '\'', actual_pretty[3] = static_cast<unsigned char>(get_or_insert(Memory, addr)), actual_pretty[4] = '\'', actual_pretty[5] = ')', actual_pretty[6] = '\0';
       }
 
       ostringstream color_phrase;
       if (color != -1) color_phrase << " in color " << color;
       if (Current_scenario && !Scenario_testing_scenario) {
         // genuine test in a mu file
-        raise_error << "\nF - " << Current_scenario->name << ": expected screen location (" << row << ", " << column << ") to contain " << curr << expected_pretty << color_phrase.str() << " instead of " << no_scientific(Memory[addr]) << actual_pretty << '\n' << end();
+        raise_error << "\nF - " << Current_scenario->name << ": expected screen location (" << row << ", " << column << ") to contain " << curr << expected_pretty << color_phrase.str() << " instead of " << no_scientific(get_or_insert(Memory, addr)) << actual_pretty << '\n' << end();
         dump_screen();
       }
       else {
         // just testing check_screen
-        raise_error << "expected screen location (" << row << ", " << column << ") to contain " << curr << expected_pretty << color_phrase.str() << " instead of " << no_scientific(Memory[addr]) << actual_pretty << '\n' << end();
+        raise_error << "expected screen location (" << row << ", " << column << ") to contain " << curr << expected_pretty << color_phrase.str() << " instead of " << no_scientific(get_or_insert(Memory, addr)) << actual_pretty << '\n' << end();
       }
       if (!Scenario_testing_scenario) {
         Passed = false;
@@ -317,7 +317,7 @@ void raw_string_stream::skip_whitespace_and_comments() {
 :(before "End Primitive Recipe Declarations")
 _DUMP_SCREEN,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$dump-screen"] = _DUMP_SCREEN;
+put(Recipe_ordinal, "$dump-screen", _DUMP_SCREEN);
 :(before "End Primitive Recipe Checks")
 case _DUMP_SCREEN: {
   break;
@@ -331,22 +331,22 @@ case _DUMP_SCREEN: {
 :(code)
 void dump_screen() {
   assert(!current_call().default_space);  // not supported
-  long long int screen_location = Memory[SCREEN];
-  int width_offset = find_element_name(Type_ordinal["screen"], "num-columns", "");
-  long long int screen_width = Memory[screen_location+width_offset];
-  int height_offset = find_element_name(Type_ordinal["screen"], "num-rows", "");
-  long long int screen_height = Memory[screen_location+height_offset];
-  int data_offset = find_element_name(Type_ordinal["screen"], "data", "");
+  long long int screen_location = get_or_insert(Memory, SCREEN);
+  int width_offset = find_element_name(get(Type_ordinal, "screen"), "num-columns", "");
+  long long int screen_width = get_or_insert(Memory, screen_location+width_offset);
+  int height_offset = find_element_name(get(Type_ordinal, "screen"), "num-rows", "");
+  long long int screen_height = get_or_insert(Memory, screen_location+height_offset);
+  int data_offset = find_element_name(get(Type_ordinal, "screen"), "data", "");
   assert(data_offset >= 0);
   long long int screen_data_location = screen_location+data_offset;  // type: address:array:character
-  long long int screen_data_start = Memory[screen_data_location];  // type: array:character
-  assert(Memory[screen_data_start] == screen_width*screen_height);
+  long long int screen_data_start = get_or_insert(Memory, screen_data_location);  // type: array:character
+  assert(get_or_insert(Memory, screen_data_start) == screen_width*screen_height);
   long long int curr = screen_data_start+1;  // skip length
   for (long long int row = 0; row < screen_height; ++row) {
     cerr << '.';
     for (long long int col = 0; col < screen_width; ++col) {
-      if (Memory[curr])
-        cerr << to_unicode(static_cast<uint32_t>(Memory[curr]));
+      if (get_or_insert(Memory, curr))
+        cerr << to_unicode(static_cast<uint32_t>(get_or_insert(Memory, curr)));
       else
         cerr << ' ';
       curr += /*size of screen-cell*/2;
diff --git a/075scenario_console.cc b/075scenario_console.cc
index 47cb5f29..4ed1d583 100644
--- a/075scenario_console.cc
+++ b/075scenario_console.cc
@@ -41,7 +41,7 @@ if (s == "console") return true;
 :(before "End Primitive Recipe Declarations")
 ASSUME_CONSOLE,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["assume-console"] = ASSUME_CONSOLE;
+put(Recipe_ordinal, "assume-console", ASSUME_CONSOLE);
 :(before "End Primitive Recipe Checks")
 case ASSUME_CONSOLE: {
   break;
@@ -57,31 +57,31 @@ case ASSUME_CONSOLE: {
   long long int size = num_events*size_of_event() + /*space for length*/1;
   ensure_space(size);
   long long int event_data_address = Current_routine->alloc;
-  Memory[event_data_address] = num_events;
+  put(Memory, event_data_address, num_events);
   ++Current_routine->alloc;
   for (long long int i = 0; i < SIZE(r.steps); ++i) {
     const instruction& curr = r.steps.at(i);
     if (curr.name == "left-click") {
-      Memory[Current_routine->alloc] = /*tag for 'touch-event' variant of 'event' exclusive-container*/2;
-      Memory[Current_routine->alloc+1+/*offset of 'type' in 'mouse-event'*/0] = TB_KEY_MOUSE_LEFT;
-      Memory[Current_routine->alloc+1+/*offset of 'row' in 'mouse-event'*/1] = to_integer(curr.ingredients.at(0).name);
-      Memory[Current_routine->alloc+1+/*offset of 'column' in 'mouse-event'*/2] = to_integer(curr.ingredients.at(1).name);
+      put(Memory, Current_routine->alloc, /*tag for 'touch-event' variant of 'event' exclusive-container*/2);
+      put(Memory, Current_routine->alloc+1+/*offset of 'type' in 'mouse-event'*/0, TB_KEY_MOUSE_LEFT);
+      put(Memory, Current_routine->alloc+1+/*offset of 'row' in 'mouse-event'*/1, to_integer(curr.ingredients.at(0).name));
+      put(Memory, Current_routine->alloc+1+/*offset of 'column' in 'mouse-event'*/2, to_integer(curr.ingredients.at(1).name));
       Current_routine->alloc += size_of_event();
     }
     else if (curr.name == "press") {
       string key = curr.ingredients.at(0).name;
       if (is_integer(key))
-        Memory[Current_routine->alloc+1] = to_integer(key);
+        put(Memory, Current_routine->alloc+1, to_integer(key));
       else if (Key.find(key) != Key.end())
-        Memory[Current_routine->alloc+1] = Key[key];
+        put(Memory, Current_routine->alloc+1, Key[key]);
       else
         raise_error << "assume-console: can't press " << key << '\n' << end();
-      if (Memory[Current_routine->alloc+1] < 256)
+      if (get_or_insert(Memory, Current_routine->alloc+1) < 256)
         // these keys are in ascii
-        Memory[Current_routine->alloc] = /*tag for 'text' variant of 'event' exclusive-container*/0;
+        put(Memory, Current_routine->alloc, /*tag for 'text' variant of 'event' exclusive-container*/0);
       else {
         // distinguish from unicode
-        Memory[Current_routine->alloc] = /*tag for 'keycode' variant of 'event' exclusive-container*/1;
+        put(Memory, Current_routine->alloc, /*tag for 'keycode' variant of 'event' exclusive-container*/1);
       }
       Current_routine->alloc += size_of_event();
     }
@@ -94,11 +94,11 @@ case ASSUME_CONSOLE: {
       long long int num_keyboard_events = unicode_length(contents);
       long long int curr = 0;
       for (long long int i = 0; i < num_keyboard_events; ++i) {
-        Memory[Current_routine->alloc] = /*tag for 'text' variant of 'event' exclusive-container*/0;
+        put(Memory, Current_routine->alloc, /*tag for 'text' variant of 'event' exclusive-container*/0);
         uint32_t curr_character;
         assert(curr < SIZE(contents));
         tb_utf8_char_to_unicode(&curr_character, &raw_contents[curr]);
-        Memory[Current_routine->alloc+/*skip exclusive container tag*/1] = curr_character;
+        put(Memory, Current_routine->alloc+/*skip exclusive container tag*/1, curr_character);
         curr += tb_utf8_char_length(raw_contents[curr]);
         Current_routine->alloc += size_of_event();
       }
@@ -107,9 +107,10 @@ case ASSUME_CONSOLE: {
   assert(Current_routine->alloc == event_data_address+size);
   // wrap the array of events in a console object
   ensure_space(size_of_console());
-  Memory[CONSOLE] = Current_routine->alloc;
+  put(Memory, CONSOLE, Current_routine->alloc);
   Current_routine->alloc += size_of_console();
-  Memory[Memory[CONSOLE]+/*offset of 'data' in container 'events'*/1] = event_data_address;
+  long long int console_address = get_or_insert(Memory, CONSOLE);
+  put(Memory, console_address+/*offset of 'data' in container 'events'*/1, event_data_address);
   break;
 }
 
@@ -227,7 +228,7 @@ scenario events-in-scenario [
 :(before "End Primitive Recipe Declarations")
 REPLACE_IN_CONSOLE,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["replace-in-console"] = REPLACE_IN_CONSOLE;
+put(Recipe_ordinal, "replace-in-console", REPLACE_IN_CONSOLE);
 :(before "End Primitive Recipe Checks")
 case REPLACE_IN_CONSOLE: {
   break;
@@ -235,17 +236,18 @@ case REPLACE_IN_CONSOLE: {
 :(before "End Primitive Recipe Implementations")
 case REPLACE_IN_CONSOLE: {
   assert(scalar(ingredients.at(0)));
-  if (!Memory[CONSOLE]) {
+  if (!get_or_insert(Memory, CONSOLE)) {
     raise_error << "console not initialized\n" << end();
     break;
   }
-  long long int console_data = Memory[Memory[CONSOLE]+1];
-  long long int size = Memory[console_data];  // array size
+  long long int console_address = get_or_insert(Memory, CONSOLE);
+  long long int console_data = get_or_insert(Memory, console_address+1);
+  long long int size = get_or_insert(Memory, console_data);  // array size
   for (long long int i = 0, curr = console_data+1; i < size; ++i, curr+=size_of_event()) {
-    if (Memory[curr] != /*text*/0) continue;
-    if (Memory[curr+1] != ingredients.at(0).at(0)) continue;
+    if (get_or_insert(Memory, curr) != /*text*/0) continue;
+    if (get_or_insert(Memory, curr+1) != ingredients.at(0).at(0)) continue;
     for (long long int n = 0; n < size_of_event(); ++n)
-      Memory[curr+n] = ingredients.at(1).at(n);
+      put(Memory, curr+n, ingredients.at(1).at(n));
   }
   break;
 }
@@ -267,7 +269,7 @@ long long int size_of_event() {
   // memoize result if already computed
   static long long int result = 0;
   if (result) return result;
-  type_tree* type = new type_tree(Type_ordinal["event"]);
+  type_tree* type = new type_tree(get(Type_ordinal, "event"));
   result = size_of(type);
   delete type;
   return result;
@@ -277,8 +279,8 @@ long long int size_of_console() {
   // memoize result if already computed
   static long long int result = 0;
   if (result) return result;
-  assert(Type_ordinal["console"]);
-  type_tree* type = new type_tree(Type_ordinal["console"]);
+  assert(get(Type_ordinal, "console"));
+  type_tree* type = new type_tree(get(Type_ordinal, "console"));
   result = size_of(type);
   delete type;
   return result;
diff --git a/080trace_browser.cc b/080trace_browser.cc
index 9c5c5e86..26c856eb 100644
--- a/080trace_browser.cc
+++ b/080trace_browser.cc
@@ -1,7 +1,7 @@
 :(before "End Primitive Recipe Declarations")
 _BROWSE_TRACE,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$browse-trace"] = _BROWSE_TRACE;
+put(Recipe_ordinal, "$browse-trace", _BROWSE_TRACE);
 :(before "End Primitive Recipe Checks")
 case _BROWSE_TRACE: {
   break;
diff --git a/081run_interactive.cc b/081run_interactive.cc
index f2a2e331..68225d3c 100644
--- a/081run_interactive.cc
+++ b/081run_interactive.cc
@@ -26,15 +26,15 @@ recipe main [
 :(before "End Primitive Recipe Declarations")
 RUN_INTERACTIVE,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["run-interactive"] = RUN_INTERACTIVE;
+put(Recipe_ordinal, "run-interactive", RUN_INTERACTIVE);
 :(before "End Primitive Recipe Checks")
 case RUN_INTERACTIVE: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(Recipe[r].name) << "'run-interactive' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'run-interactive' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
     break;
   }
   if (!is_mu_string(inst.ingredients.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "first ingredient of 'run-interactive' should be a string, but got " << inst.ingredients.at(0).to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'run-interactive' should be a string, but got " << inst.ingredients.at(0).to_string() << '\n' << end();
     break;
   }
   break;
@@ -69,7 +69,7 @@ Track_most_recent_products = false;
 // all warnings.
 // returns true if successfully called (no errors found during load and transform)
 bool run_interactive(long long int address) {
-  assert(Recipe_ordinal.find("interactive") != Recipe_ordinal.end() && Recipe_ordinal["interactive"] != 0);
+  assert(Recipe_ordinal.find("interactive") != Recipe_ordinal.end() && get(Recipe_ordinal, "interactive") != 0);
   // try to sandbox the run as best you can
   // todo: test this
   if (!Current_scenario) {
@@ -78,8 +78,8 @@ bool run_interactive(long long int address) {
   }
   string command = trim(strip_comments(read_mu_string(address)));
   if (command.empty()) return false;
-  Recipe.erase(Recipe_ordinal["interactive"]);
-  Name[Recipe_ordinal["interactive"]].clear();
+  Recipe.erase(get(Recipe_ordinal, "interactive"));
+  Name[get(Recipe_ordinal, "interactive")].clear();
   run_code_begin();
   // don't kill the current routine on parse errors
   routine* save_current_routine = Current_routine;
@@ -103,7 +103,7 @@ bool run_interactive(long long int address) {
     trace(9999, "trace") << "run-interactive: incrementing callstack depth to " << Save_trace_stream->callstack_depth << end();
     assert(Save_trace_stream->callstack_depth < 9000);  // 9998-101 plus cushion
   }
-  Current_routine->calls.push_front(call(Recipe_ordinal["sandbox"]));
+  Current_routine->calls.push_front(call(get(Recipe_ordinal, "sandbox")));
   return true;
 }
 
@@ -167,7 +167,7 @@ add 2, 2]
 :(before "End Primitive Recipe Declarations")
 _START_TRACKING_PRODUCTS,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$start-tracking-products"] = _START_TRACKING_PRODUCTS;
+put(Recipe_ordinal, "$start-tracking-products", _START_TRACKING_PRODUCTS);
 :(before "End Primitive Recipe Checks")
 case _START_TRACKING_PRODUCTS: {
   break;
@@ -181,7 +181,7 @@ case _START_TRACKING_PRODUCTS: {
 :(before "End Primitive Recipe Declarations")
 _STOP_TRACKING_PRODUCTS,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$stop-tracking-products"] = _STOP_TRACKING_PRODUCTS;
+put(Recipe_ordinal, "$stop-tracking-products", _STOP_TRACKING_PRODUCTS);
 :(before "End Primitive Recipe Checks")
 case _STOP_TRACKING_PRODUCTS: {
   break;
@@ -195,7 +195,7 @@ case _STOP_TRACKING_PRODUCTS: {
 :(before "End Primitive Recipe Declarations")
 _MOST_RECENT_PRODUCTS,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$most-recent-products"] = _MOST_RECENT_PRODUCTS;
+put(Recipe_ordinal, "$most-recent-products", _MOST_RECENT_PRODUCTS);
 :(before "End Primitive Recipe Checks")
 case _MOST_RECENT_PRODUCTS: {
   break;
@@ -210,7 +210,7 @@ case _MOST_RECENT_PRODUCTS: {
 :(before "End Primitive Recipe Declarations")
 SAVE_ERRORS_WARNINGS,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["save-errors-warnings"] = SAVE_ERRORS_WARNINGS;
+put(Recipe_ordinal, "save-errors-warnings", SAVE_ERRORS_WARNINGS);
 :(before "End Primitive Recipe Checks")
 case SAVE_ERRORS_WARNINGS: {
   break;
@@ -225,7 +225,7 @@ case SAVE_ERRORS_WARNINGS: {
 :(before "End Primitive Recipe Declarations")
 SAVE_APP_TRACE,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["save-app-trace"] = SAVE_APP_TRACE;
+put(Recipe_ordinal, "save-app-trace", SAVE_APP_TRACE);
 :(before "End Primitive Recipe Checks")
 case SAVE_APP_TRACE: {
   break;
@@ -240,7 +240,7 @@ case SAVE_APP_TRACE: {
 :(before "End Primitive Recipe Declarations")
 _CLEANUP_RUN_INTERACTIVE,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["$cleanup-run-interactive"] = _CLEANUP_RUN_INTERACTIVE;
+put(Recipe_ordinal, "$cleanup-run-interactive", _CLEANUP_RUN_INTERACTIVE);
 :(before "End Primitive Recipe Checks")
 case _CLEANUP_RUN_INTERACTIVE: {
   break;
@@ -356,7 +356,7 @@ string strip_comments(string in) {
 long long int stringified_value_of_location(long long int address) {
   // convert to string
   ostringstream out;
-  out << no_scientific(Memory[address]);
+  out << no_scientific(get_or_insert(Memory, address));
   return new_mu_string(out.str());
 }
 
@@ -403,15 +403,15 @@ void truncate(string& x) {
 :(before "End Primitive Recipe Declarations")
 RELOAD,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["reload"] = RELOAD;
+put(Recipe_ordinal, "reload", RELOAD);
 :(before "End Primitive Recipe Checks")
 case RELOAD: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(Recipe[r].name) << "'reload' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'reload' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
     break;
   }
   if (!is_mu_string(inst.ingredients.at(0))) {
-    raise_error << maybe(Recipe[r].name) << "first ingredient of 'reload' should be a string, but got " << inst.ingredients.at(0).original_string << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'reload' should be a string, but got " << inst.ingredients.at(0).original_string << '\n' << end();
     break;
   }
   break;
@@ -420,7 +420,7 @@ case RELOAD: {
 case RELOAD: {
   // clear any containers in advance
   for (long long int i = 0; i < SIZE(recently_added_types); ++i) {
-    Type_ordinal.erase(Type[recently_added_types.at(i)].name);
+    Type_ordinal.erase(get(Type, recently_added_types.at(i)).name);
     Type.erase(recently_added_types.at(i));
   }
   string code = read_mu_string(ingredients.at(0).at(0));
diff --git a/082persist.cc b/082persist.cc
index a43a4395..774ce08f 100644
--- a/082persist.cc
+++ b/082persist.cc
@@ -5,11 +5,11 @@
 :(before "End Primitive Recipe Declarations")
 RESTORE,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["restore"] = RESTORE;
+put(Recipe_ordinal, "restore", RESTORE);
 :(before "End Primitive Recipe Checks")
 case RESTORE: {
   if (SIZE(inst.ingredients) != 1) {
-    raise_error << maybe(Recipe[r].name) << "'restore' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'restore' requires exactly one ingredient, but got " << inst.to_string() << '\n' << end();
     break;
   }
   string filename;
@@ -20,7 +20,7 @@ case RESTORE: {
     ;
   }
   else {
-    raise_error << maybe(Recipe[r].name) << "first ingredient of 'restore' should be a string, but got " << inst.ingredients.at(0).to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'restore' should be a string, but got " << inst.ingredients.at(0).to_string() << '\n' << end();
     break;
   }
   break;
@@ -69,11 +69,11 @@ string slurp(const string& filename) {
 :(before "End Primitive Recipe Declarations")
 SAVE,
 :(before "End Primitive Recipe Numbers")
-Recipe_ordinal["save"] = SAVE;
+put(Recipe_ordinal, "save", SAVE);
 :(before "End Primitive Recipe Checks")
 case SAVE: {
   if (SIZE(inst.ingredients) != 2) {
-    raise_error << maybe(Recipe[r].name) << "'save' requires exactly two ingredients, but got " << inst.to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "'save' requires exactly two ingredients, but got " << inst.to_string() << '\n' << end();
     break;
   }
   if (is_literal_string(inst.ingredients.at(0))) {
@@ -83,11 +83,11 @@ case SAVE: {
     ;
   }
   else {
-    raise_error << maybe(Recipe[r].name) << "first ingredient of 'save' should be a string, but got " << inst.ingredients.at(0).to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "first ingredient of 'save' should be a string, but got " << inst.ingredients.at(0).to_string() << '\n' << end();
     break;
   }
   if (!is_mu_string(inst.ingredients.at(1))) {
-    raise_error << maybe(Recipe[r].name) << "second ingredient of 'save' should be an address:array:character, but got " << inst.ingredients.at(1).to_string() << '\n' << end();
+    raise_error << maybe(get(Recipe, r).name) << "second ingredient of 'save' should be an address:array:character, but got " << inst.ingredients.at(1).to_string() << '\n' << end();
     break;
   }
   break;