<buttonid="sidebar-toggle"class="icon-button"type="button"title="Toggle Table of Contents"aria-label="Toggle Table of Contents"aria-controls="sidebar">
<ahref="print.html"title="Print this book"aria-label="Print this book">
<iid="print-button"class="fa fa-print"></i>
</a>
</div>
</div>
<divid="search-wrapper"class="hidden">
<formid="searchbar-outer"class="searchbar-outer">
<inputtype="search"id="searchbar"name="searchbar"placeholder="Search this book ..."aria-controls="searchresults-outer"aria-describedby="searchresults-header">
<p>This page describes the unreleased "Salsa 2022" version, which is a major departure from older versions of salsa. The code here works but is only available on github and from the <code>salsa-2022</code> crate.</p>
<p>You start out with an input that has some value.
You invoke your program to get back a result.
Some time later, you modify the input and invoke your program again.
<strong>Our goal is to make this second call faster by re-using some of the results from the first call.</strong></p>
<p>In reality, of course, you can have many inputs and "your program" may be many different methods and functions defined on those inputs.
But this picture still conveys a few important concepts:</p>
<ul>
<li>Salsa separates out the "incremental computation" (the function <code>your_program</code>) from some outer loop that is defining the inputs.</li>
<li>Salsa gives you the tools to define <code>your_program</code>.</li>
<li>Salsa assumes that <code>your_program</code> is a purely deterministic function of its inputs, or else this whole setup makes no sense.</li>
<li>The mutation of inputs always happens outside of <code>your_program</code>, as part of this master loop.</li>
<p>Each time you run your program, salsa remembers the values of each computation in a <strong>database</strong>.
When the inputs change, it consults this database to look for values that can be reused.
The database is also used to implement interning (making a canonical version of a value that can be copied around and cheaply compared for equality) and other convenient salsa features.</p>
<h3id="salsa-structs-are-just-an-integer"><aclass="header"href="#salsa-structs-are-just-an-integer">Salsa structs are just an integer</a></h3>
<p>The <code>ProgramFile</code> struct generates by the <code>salsa::input</code> macro doesn't actually store any data. It's just a newtyped integer id:</p>
<p>Invoking the accessor clones the value from the database.
Sometimes this is not what you want, so you can annotate fields with <code>#[return_ref]</code> to indicate that they should return a reference into the database instead:</p>
<p>When you call a tracked function, salsa will track which inputs it accesses (in this example, <code>file.contents(db)</code>).
It will also memoize the return value (the <code>Ast</code>, in this case).
If you call a tracked function twice, salsa checks if the inputs have changed; if not, it can return the memoized value.
The algorithm salsa uses to decide when a tracked function needs to be re-executed is called the <ahref="./reference/algorithm.html">red-green algorithm</a>, and it's where the name salsa comes from.</p>
<p>Tracked functions have to follow a particular structure:</p>
<ul>
<li>They must take a <code>&</code>-reference to the database as their first argument.
<ul>
<li>Note that because this is an <code>&</code>-reference, it is not possible to create or modify inputs during a tracked function!</li>
</ul>
</li>
<li>They must take a "salsa struct" as the second argument -- in our example, this is an input struct, but there are other kinds of salsa structs we'll describe shortly.</li>
<li>They <em>can</em> take additional arguments, but it's faster and better if they don't.</li>
</ul>
<p>Tracked functions can return any clone-able type. A clone is required since, when the value is cached, the result will be cloned out of the database. Tracked functions can also be annotated with <code>#[return_ref]</code> if you would prefer to return a reference into the database instead (if <code>parse_file</code> were so annotated, then callers would actually get back an <code>&Ast</code>, for example).</p>
<p><strong>Tracked structs</strong> are intermediate structs created during your computation.
Like inputs, their fields are stored inside the database, and the struct itself just wraps an id.
Unlike inputs, they can only be created inside a tracked function, and their fields can never change once they are created.
Getter methods are provided to read the fields, but there are no setter methods<supclass="footnote-reference"><ahref="#specify">1</a></sup>. Example:</p>
<p>When a tracked function is re-executed because its inputs have changed, the tracked structs it creates in the new execution are matched against those from the old execution, and the values of their fields are compared.
If the field values have not changed, then other tracked functions that only read those fields will not be re-executed.</p>
<p>Normally, tracked structs are matched up by the order in which they are created.
For example, the first <code>Ast</code> that is created by <code>parse_file</code> in the old execution will be matched against the first <code>Ast</code> created by <code>parse_file</code> in the new execution.
In our example, <code>parse_file</code> only ever creates a single <code>Ast</code>, so this works great.
Sometimes, however, it doesn't work so well.
For example, imagine that we had a tracked struct for items in the file:</p>
<p>Maybe our parser first creates an <code>Item</code> with the name <code>foo</code> and then later a second <code>Item</code> with the name <code>bar</code>.
Then the user changes the input to reorder the functions.
Although we are still creating the same number of items, we are now creating them in the reverse order, so the naive algorithm will match up the <em>old</em><code>foo</code> struct with the new <code>bar</code> struct.
This will look to salsa as though the <code>foo</code> function was renamed to <code>bar</code> and the <code>bar</code> function was renamed to <code>foo</code>.
We'll still get the right result, but we might do more recomputation than we needed to do if we understood that they were just reordered.</p>
<p>To address this, you can tag fields in a tracked struct as <code>#[id]</code>. These fields are then used to "match up" struct instances across executions:</p>
<h3id="specified-the-result-of-tracked-functions-for-particular-structs"><aclass="header"href="#specified-the-result-of-tracked-functions-for-particular-structs">Specified the result of tracked functions for particular structs</a></h3>
<p>Sometimes it is useful to define a tracked function but specify its value for some particular struct specially.
For example, maybe the default way to compute the representation for a function is to read the AST, but you also have some built-in functions in your language and you want to hard-code their results.
This can also be used to simulate a field that is initialized after the tracked struct is created.</p>
To enable this method, you need to add the <code>specify</code> flag to the function to alert users that its value may sometimes be specified externally.</p>
<p>As with input and tracked structs, the <code>Word</code> struct itself is just a newtyped integer, and the actual data is stored in the database.</p>
<p>You can create a new interned struct using <code>new</code>, just like with input and tracked structs:</p>
<p>When you create two interned structs with the same field values, you are guaranted to get back the same integer id. So here, we know that <code>assert_eq!(w1, w3)</code> is true and <code>assert_ne!(w1, w2)</code>.</p>
<p>You can access the fields of an interned struct using a getter, like <code>word.text(db)</code>. These getters respect the <code>#[return_ref]</code> annotation. Like tracked structs, the fields of interned structs are immutable.</p>
<p>The final salsa concept are <strong>accumulators</strong>. Accumulators are a way to report errors or other "side channel" information that is separate from the main return value of your function.</p>
<p>To create an accumulator, you declare a type as an <em>accumulator</em>:</p>
<p>Then later, from outside the execution, you can ask for the set of diagnostics that were accumulated by some particular tracked function. For example, imagine that we have a type-checker and, during type-checking, it reports some diagnostics:</p>