Skip to content

Commit

Permalink
Second pass edits
Browse files Browse the repository at this point in the history
  • Loading branch information
amyrhoda committed Feb 26, 2016
1 parent 9075d2f commit c754422
Showing 1 changed file with 43 additions and 42 deletions.
85 changes: 43 additions & 42 deletions contingent/contingent.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ and `toctree` command might be:
• Installation
• Newcomers' Tutorial
• Newcomers Tutorial
• Hello, World
• Adding Logging
Expand All @@ -123,8 +123,8 @@ and `toctree` command might be:
This table of contents, as you can see, is a mash-up
of information from four different files.
While its basic order and structure come from `index.rst`,
the actual title of each chapter and section
is pulled from the three chapter source files themselves.
the actual titles of each chapter and section
are pulled from the three chapter source files themselves.

If you later reconsider the tutorial’s chapter title —
after all, the word “newcomer” sounds so quaint,
Expand All @@ -133,8 +133,8 @@ then you would edit the first line of `tutorial.rst`
and write something better:

```
-Newcomers' Tutorial
+Beginners' Tutorial
-Newcomers Tutorial
+Beginners Tutorial
==================
Welcome to the tutorial!
Expand Down Expand Up @@ -165,7 +165,7 @@ Sphinx has rebuilt everything so that the output is consistent.
What if your edit to `tutorial.rst` is more minor?

```
Beginners' Tutorial
Beginners Tutorial
===================
-Welcome to the tutorial!
Expand Down Expand Up @@ -238,7 +238,7 @@ of the tutorial chapter into the cross reference’s anchor tag:
```html
<p>Before reading this, try reading our
<a class="reference internal" href="tutorial.html">
<em>Beginners' Tutorial</em>
<em>Beginners Tutorial</em>
</a>!</p>
```

Expand Down Expand Up @@ -296,19 +296,19 @@ its solution is of equally long lineage:

If you remove all of the output,
you are guaranteed a complete rebuild!
Some projects even alias `rm` `-r` a target named `clean`
Some projects even alias `rm` `-r` to a target named `clean`
so that only a quick `make` `clean` is necessary to wipe the slate.

By eliminating every copy of every intermediate or output asset,
a hefty `rm` `-r` is able to force the build to start over again
with nothing cached — with no memory of its earlier state
that could possibly lead to a stale product!
that could possibly lead to a stale product.

But could we develop a better approach?

What if your build system were a persistent process
that noticed every chapter title, every section title,
and every cross referenced phrase
and every cross-referenced phrase
as it passed from the source code of one document
into the text of another?
Its decisions about whether to rebuild other documents
Expand All @@ -322,11 +322,12 @@ but which learned the dependencies between files as they were built —
that added and removed dependencies dynamically
as cross references were added, updated, and deleted.

In the sections that follow we will construct such a tool in Python,
In the sections that follow we will construct such a tool,
named Contingent,
that guarantees correctness in the presence of dynamic dependencies
in Python.
Contingent guarantees correctness in the presence of dynamic dependencies
while performing the fewest possible rebuild steps.
While Contingent can be applied to any problem domain,
While it can be applied to any problem domain,
we will run it against a small version of the problem outlined above.

## Linking Tasks to Make a Graph
Expand All @@ -337,7 +338,7 @@ for example,
each produce a corresponding HTML output file.
The most natural way to express these relationships
is as a collection of boxes and arrows —
or, in mathematician terminology, *nodes* and *edges*
or, in mathematical terminology, *nodes* and *edges*
to form a *graph* (\aosafigref{500l.contingent.graph}).

\aosafigure[240pt]{contingent-images/figure1.png}{Three files generated by parsing three input texts.}{500l.contingent.graph}
Expand Down Expand Up @@ -397,7 +398,7 @@ by which each value is indexed,
instead of using automatic integer indexing as the tuple and list do.
The lookup is backed by a hash table,
which means that dict key lookup runs at the same speed
whether the dict has a dozen or a million keys!
whether the dict has a dozen or a million keys.

```python
{'ssh': 22, 'telnet': 23, 'domain': 53, 'http': 80}
Expand Down Expand Up @@ -449,13 +450,14 @@ A build system like Contingent
needs to understand the relationship between a given node
and all the nodes connected to it.
For example, when `api.rst` changes,
Contingent needs to know which assets
are affected by that change, if any,
Contingent needs to know which assets, if any,
are affected by that change
in order to minimize the work performed
while also ensuring a complete build.
To answer this question —
“what nodes are downstream from `api.rst`?” —
we need to examine the *outgoing* edges from `api.rst`.

But building the dependency graph requires that
Contingent be concerned with a node's *inputs* as well.
What inputs were used, for example,
Expand Down Expand Up @@ -550,7 +552,7 @@ and a hardly less-frequent subject of heated debate
among their adherents and detractors.
Classes were once thought important enough that
entire educational curricula were designed around them,
and the majority of popular programming languanges
and the majority of popular programming languages
include dedicated syntax for defining and using them.

But it turns out that classes are often orthogonal
Expand Down Expand Up @@ -580,7 +582,7 @@ You can then pass `Address` objects around
where otherwise you would have had anonymous tuples.
Code becomes easier to read and easier to write.
But using a class instance does not really change
any of the questions we faced above when doing data design:
any of the questions we faced above when doing data design;
it just provides a prettier and less anonymous container.

The true value of classes, then,
Expand Down Expand Up @@ -646,8 +648,7 @@ The Python language and community explicitly and intentionally emphasize
using simple, generic data structures to solve problems,
instead of creating custom classes for every minute detail
of the problem we want to tackle.
This is one facet of the notion of “Pythonic” solutions that you may
have read about.
This is one facet of the notion of “Pythonic” solutions:
Pythonic solutions try to
minimize syntactic overhead
and leverage Python's powerful built-in tools
Expand Down Expand Up @@ -677,8 +678,8 @@ to signal that an attribute is private.
This convention is one way the community suggests
that programmers pass messages and warnings
through space and time to each other.
Recognizing the need to signal differences among
public versus internal object attributes,
Recognizing the need to signal differences between
public and internal object attributes,
the community adopted the single leading underscore
as a concise and fairly consistent indicator
to other programmers,
Expand Down Expand Up @@ -727,7 +728,7 @@ set()

Structuring our implementation this way means that
each key’s first use can look identical
to second-and-subsequent-times that a particular key is used:
to second and subsequent times that a particular key is used:

```python
>>> consequences_of['index.rst'].add('index.html')
Expand Down Expand Up @@ -774,9 +775,9 @@ without having to learn how to traverse our data structure:
for b in self.sorted(self._consequences_of[a])]
```

The `Graph.sorted()` method, if you want to examine it later,
The `Graph.sorted()` method
makes an attempt to sort the nodes
in case they have a natural sort order
in a natural sort order
(such as alphabetical)
that can provide a stable output order for the user.

Expand Down Expand Up @@ -863,7 +864,7 @@ for the various artifacts in our project's documentation.
We now have a way for Contingent
to keep track of tasks and the relationships between them.
If we look more closely at Figure 2, however,
we see that it is actually a little hand wavy and vague:
we see that it is actually a little hand-wavy and vague:
*how* is `api.html` produced from `api.rst`?
How do we know that `index.html` needs the title from the tutorial?
And how is this dependency resolved?
Expand Down Expand Up @@ -992,9 +993,9 @@ Because the format is so simple,
the parser is a little silly, admittedly,
but it illustrates the interpretive responsibilities
that parsers are required to carry out.
Parsing in general is a very interesting subject
(Parsing in general is a very interesting subject
and many books have been written
either partially or completely about it.
either partially or completely about it.)
In a system like Sphinx,
the parser must understand the many markup tokens,
directives, and commands defined by the system,
Expand Down Expand Up @@ -1102,7 +1103,7 @@ similar to the stack of live execution frames
that Python maintains to remember which function to continue running
when the current one returns.

Every time that a new task is invoked,
Every time a new task is invoked,
Contingent can assume that it has been called —
and that its output will be used —
by the task currently at the top of the stack.
Expand Down Expand Up @@ -1139,7 +1140,7 @@ Here is what the `task` decorator boilerplate looks like:

This is an entirely typical Python decorator declaration.
It can then be applied to a function
by naming it after a `@` character atop the `def`
by naming it after an `@` character atop the `def`
that creates the function:

```python
Expand Down Expand Up @@ -1202,7 +1203,7 @@ This wrapper performs several crucial maintenance steps:

5. Invoke the task
inside of a `try...finally` block
that ensures we correctly remove the finished task from the stack
that ensures we correctly remove the finished task from the stack,
even if it dies by raising an exception.

6. Return the task’s return value,
Expand Down Expand Up @@ -1255,7 +1256,7 @@ read('tutorial.txt')
```

The consequence of re-reading the `tutorial.txt` file
and finding its contents have changed
and finding that its contents have changed
is that we need to re-execute the `parse()` routine for that document.
What happens if we render the entire set of documents?
Will Contingent be able to learn the entire build process
Expand Down Expand Up @@ -1310,7 +1311,7 @@ if the inputs to any tasks change.

Once the initial build has run to completion,
Contingent needs to monitor the input files for changes.
When the user finishes a new edit and runs “Save,”
When the user finishes a new edit and runs “Save”,
both the `read()` method and its consequences need to be invoked.

This will require us to walk the graph in the opposite order
Expand All @@ -1325,10 +1326,10 @@ and we need to figure out what consequences lie downstream.
The process of compiling consequences is a recursive one,
as each consequence can itself have further tasks that depended on it.
We could perform this recursion manually
through repeated calls to the graph
(note that we are here taking advantage
through repeated calls to the graph.
(Note that we are here taking advantage
of the fact that the Python prompt saves the last value displayed
under the name `_` for use in the subsequent expression):
under the name `_` for use in the subsequent expression.)

```python
>>> task = Task(read, ('api.txt',))
Expand Down Expand Up @@ -1372,7 +1373,7 @@ so that it appears only after the tasks that are its inputs.
This intelligence is powered by the classic depth-first implementation
of a topological sort,
an algorithm which winds up being fairly easy to write in Python
through a hidden a recursive helper function.
through a hidden recursive helper function.
Check out the `graphlib.py` source code for the details.

If, upon detecting a change,
Expand Down Expand Up @@ -1532,18 +1533,18 @@ calling title_of('tutorial.txt')
Success!
Only one document got rebuilt.
The fact that `title_of()`, given a new input document,
nevertheless returned the same value means that all further
nevertheless returned the same value, means that all further
downstream tasks were insulated from the change
and did not get re-invoked.

## Conclusion

There exist languages and programming methodologies
under which Contingent would be a suffocating forest of tiny classes
giving useless and verbose names to every concept in the problem domain.
under which Contingent would be a suffocating forest of tiny classes,
with useless and verbose names given to every concept in the problem domain.

When programming Contingent in Python, however,
we skipped the creation of a dozen classes that could have existed,
we skipped the creation of a dozen possible classes
like `TaskArgument` and `CachedResult` and `ConsequenceList`.
We instead drew upon Python’s strong tradition
of solving generic problems with generic data structures,
Expand Down

0 comments on commit c754422

Please sign in to comment.