On Contexts
Or, how I wish for a more explicit world.
Consider a directed graph. Given a library with graph manipulation and traversal capabilities like weave, you can easily find in-and-out going arrows from a node (arrows, arrows_in, arrows_out) as well as use simple moves to get the source or target of arrows once you have them (to_src, to_tgt). Getting all the neighbors of a node amounts to to_tgt(arrows_out(·)).
Imagine now that you want to work with an undirected graph. The setup made within weave is very digraph-oriented. In my experience, directedness is easier to ignore than to implement from a basis in undirected graphs. This leads us to the following questions: do we need to have a structural construction of a bidirectional arrow/undirected edge, or can the whole thing be made of different operations on a single, normal arrow, disregarding its direction and going the other way? It all depends on your situation in the end, but the change should be given explicit context by the structure around it.
In the example above, the bidirectional mints explored in previous entries convey our intent to have a sort of dual arrow that can be traversed in an endpoint-agnostic way that also supports normal arrow traversal. They aren't good for much more than exactly that. This structure, without any data (and remember that data is important because semantic systems query and operate on data!) operates to present the wanted semantics of an undirected edge. The operation used to traverse it (hop) is more widely applicable than the one for traversing arrows, so weave takes it as a ground truth, even though it’s one 1 primitive operation larger. If we instead focus on the solution where we just use raw dual operations on the arrows, we’re not supporting semantics through structure - we’re just doing things. Doing things is good, that’s what these posts are for the most part, but we need to solidify it somehow. With science!

A good first step after doing things is checking how general the behavior we’ve created is. Maybe it can be applied widely, maybe it can even be a new ground truth! If so, lift it up and let us all use it, that’s cool.
If not, create a named context. Contexts, although they still don’t exist in code, are all about named executive semantics - about how things are done when we run them.
For example, within your new as_undirected_graph context, running the functions arrows_in, arrows_out, and arrows returns the same set, as it ignores direction. This is what this context does to your execution. To have it affect things, it needs to be applied to a carrier structure, usually a hierarchy within which it will apply. Contexts allow interpretation, and a structured, limited, and explicit “reassignment” of ground rules.
Many ECS systems can be rewritten as contexts that execute their systemic code when some tag is added, for example. The first thing that came to mind is preparing a binary tree of operations and numbers within a hierarchy with an example eval_arithmetic context, and then attaching a “Calculate” tag which triggers the context to gobble up the tree and produce a single node. Having contexts be this wide and open allows for code lifting: taking what had to, until now, be written in code, and wrapping it in a couple of motifs, executed by an uplifter context.
If it isn't obvious, the idea of contexts fills me with joy. They solve many of the problems I initially had, such as the one that this post started with - contexts are usually marks added to a motif whose dependents now take peculiar shapes following peculiar rules, so they are in fact upheld by structure even though they themselves change algorithmics. Complex topics such as how to do transitive closures, operations with results, chaining of operations represented via motifs, requiring certain components to exist, as well as error reporting become easier once this tool is brought in. There’s a lot of open questions about the proper code introduction for contexts, which is mostly why they haven’t been coded up yet. I can already tell that contexts will change how most of weave works right now, meaning that they need to be bootstrapped somewhat recursively, a feat I'm not ready for yet. But we're getting there!


How do we determine whether a behavior should be lifted to a context versus left ad-hoc?