//: Containers contain a fixed number of elements of different types. :(before "End Mu Types Initialization") //: We'll use this container as a running example, with two number elements. type_ordinal point = put(Type_ordinal, "point", Next_type_ordinal++); get_or_insert(Type, point); // initialize get(Type, point).kind = CONTAINER; get(Type, point).name = "point"; get(Type, point).elements.push_back(reagent("x:number")); get(Type, point).elements.push_back(reagent("y:number")); //: Containers can be copied around with a single instruction just like //: numbers, no matter how large they are. //: Tests in this layer often explicitly set up memory before reading it as a //: container. Don't do this in general. I'm tagging exceptions with /raw to //: avoid errors. :(scenario copy_multiple_locations) def main [ 1:number <- copy 34 2:number <- copy 35 3:point <- copy 1:point/unsafe ] +mem: storing 34 in location 3 +mem: storing 35 in location 4 //: trying to copy to a differently-typed destination will fail :(scenario copy_checks_size) % Hide_errors = true; def main [ 2:point <- copy 1:number ] +error: main: can't copy 1:number to 2:point; types don't match :(before "End Mu Types Initialization") // A more complex container, containing another container as one of its // elements. type_ordinal point_number = put(Type_ordinal, "point-number", Next_type_ordinal++); get_or_insert(Type, point_number); // initialize get(Type, point_number).kind = CONTAINER; get(Type, point_number).name = "point-number"; get(Type, point_number).elements.push_back(reagent("xy:point")); get(Type, point_number).elements.push_back(reagent("z:number")); :(scenario copy_handles_nested_container_elements) def main [ 12:number <- copy 34 13:number <- copy 35 14:number <- copy 36 15:point-number <- copy 12:point-number/unsafe ] +mem: storing 36 in location 17 //: products of recipes can include containers :(scenario return_container) def main [ 3:point <- f 2 ] def f [ 12:number <- next-ingredient 13:number <- copy 35 return 12:point/raw ] +run: result 0 is [2, 35] +mem: storing 2 in location 3 +mem: storing 35 in location 4 //: Containers can be checked for equality with a single instruction just like //: numbers, no matter how large they are. :(scenario compare_multiple_locations) def main [ 1:number <- copy 34 # first 2:number <- copy 35 3:number <- copy 36 4:number <- copy 34 # second 5:number <- copy 35 6:number <- copy 36 7:boolean <- equal 1:point-number/raw, 4:point-number/unsafe ] +mem: storing 1 in location 7 :(scenario compare_multiple_locations_2) def main [ 1:number <- copy 34 # first 2:number <- copy 35 3:number <- copy 36 4:number <- copy 34 # second 5:number <- copy 35 6:number <- copy 37 # different 7:boolean <- equal 1:point-number/raw, 4:point-number/unsafe ] +mem: storing 0 in location 7 //: Global data structure for container metadata. //: Can't put this in type_info because later layers will add support for more //: complex type trees where metadata depends on *combinations* of types. :(before "struct reagent") struct container_metadata { int size; vector offset; // End container_metadata Fields container_metadata() :size(0) { // End container_metadata Constructor } }; :(before "End reagent Fields") container_metadata metadata; // can't be a pointer into Container_metadata because we keep changing the base storage when we save/restore snapshots :(before "End reagent Copy Operator") metadata = other.metadata; :(before "End reagent Copy Constructor") metadata = other.metadata; :(before "End Globals") // todo: switch to map after figuring out how to consistently compare type trees vector > Container_metadata, Container_metadata_snapshot; :(before "End save_snapshots") Container_metadata_snapshot = Container_metadata; :(before "End restore_snapshots") restore_container_metadata(); :(before "End One-time Setup") atexit(clear_container_metadata); :(code) // invariant: Container_metadata always contains a superset of Container_metadata_snapshot void restore_container_metadata() { for (int i = 0; i < SIZE(Container_metadata); ++i) { assert(Container_metadata.at(i).first); if (i < SIZE(Container_metadata_snapshot)) { assert(Container_metadata.at(i).first == Container_metadata_snapshot.at(i).first); continue; } delete Container_metadata.at(i).first; Container_metadata.at(i).first = NULL; } Container_metadata.resize(SIZE(Container_metadata_snapshot)); } void clear_container_metadata() { Container_metadata_snapshot.clear(); for (int i = 0; i < SIZE(Container_metadata); ++i) { delete Container_metadata.at(i).first; Container_metadata.at(i).first = NULL; } Container_metadata.clear(); } //: do no work in size_of, simply lookup Container_metadata :(before "End size_of(reagent r) Cases") if (r.metadata.size) return r.metadata.size; :(before "End size_of(type) Cases") if (type->value == -1) return 1; // error value, but we'll raise it elsewhere if (type->value == 0) { assert(!type->left && !type->right); return 1; } if (!contains_key(Type, type->value)) { raise << "no such type " << type->value << '\n' << end(); return 0; } type_info t = get(Type, type->value); if (t.kind == CONTAINER) { // Compute size_of Container return get(Container_metadata, type).size; } //: precompute Container_metadata before we need size_of //: also store a copy in each reagent in each instruction in each recipe :(after "Begin Instruction Modifying Transform
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Mu - immutable-error.mu</title>
<meta name="Generator" content="Vim/8.0">
<meta name="plugin-version" content="vim7.4_v2">
<meta name="syntax" content="none">
<meta name="settings" content="number_lines,use_css,pre_wrap,no_foldcolumn,expand_tabs,line_ids,prevent_copy=">
<meta name="colorscheme" content="minimal">
<style type="text/css">
<!--
pre { white-space: pre-wrap; font-family: monospace; color: #aaaaaa; background-color: #080808; }
body { font-size: 12pt; font-family: monospace; color: #aaaaaa; background-color: #080808; }
a { color:#eeeeee; text-decoration: none; }
a:hover { text-decoration: underline; }
* { font-size: 12pt; font-size: 1em; }
.muRecipe { color: #ff8700; }
.LineNr { color: #444444; }
.Constant { color: #00a0a0; }
.Special { color: #c00000; }
.Comment { color: #9090ff; }
.Comment a { color:#0000ee; text-decoration:underline; }
-->
</style>

<script type='text/javascript'>
<!--

/* function to open any folds containing a jumped-to line before jumping to it */
function JumpToLine()
{
  var lineNum;
  lineNum = window.location.hash;
  lineNum = lineNum.substr(1); /* strip off '#' */

  if (lineNum.indexOf('L') == -1) {
    lineNum = 'L'+lineNum;
  }
  lineElem = document.getElementById(lineNum);
  /* Always jump to new location even if the line was hidden inside a fold, or
   * we corrected the raw number to a line ID.
   */
  if (lineElem) {
    lineElem.scrollIntoView(true);
  }
  return true;
}
if ('onhashchange' in window) {
  window.onhashchange = JumpToLine;
}

-->
</script>
</head>
<body onload='JumpToLine();'>
<pre id='vimCodeElement'>
<span id="L1" class="LineNr"> 1 </span><span class="Comment"># compare mutable.mu</span>
<span id="L2" class="LineNr"> 2 </span>
<span id="L3" class="LineNr"> 3 </span><span class="muRecipe">def</span> <a href='immutable-error.mu.html#L3'>main</a> [
<span id="L4" class="LineNr&quo