CU5 — The DSL
from somatize import Filter, Graph
g = Graph.somatize(Source() >> (Left().named("left") | Right().named("right")) >> Mean())g.forward(0)let (graph, catalog) = (filter("source", Add(1.0)) >> (filter("left", Add(10.0)) | filter("right", Add(100.0))) >> filter("join", Mean)).somatize()?;Status: closed. Same tests, plus build.rs and test_dsl.py.
>> chains, | opens branches, and a >> after some open branches closes them
— which is CU4’s fan-in: the node on the right receives the map. The expression
above is the diamond.
Decisions taken
Section titled “Decisions taken”- The same syntax in both languages. In Rust it falls out of implementing
std::ops::ShrandBitOron a type of our own; no macro needed (macro_rules!would give syntax the operators do not, but that is not needed here). The precedence matches too:>>binds tighter than|, so the branches go in parentheses in both. - It is called
somatize, which is the project’s verb. In Python it is a classmethod ofGraph; in Rust, a method ofWire, because it returns two things — the structure and the store — and neither contains the other. - There is a Python class on top of the Rust one.
somatizewalks an expression of Python objects, so it cannot be in Rust; and a#[pyclass]is an immutable type, so it cannot be hung on it at import time either. It is declared in a subclass body, which is also the only thinghelp(), an IDE and mypy can see. It is the same structure as the original Soma (soma/_graph.py), and for the same reasons. - The base class is abstract, and inheritance is what decides. It requires
its method with
@abstractmethod, so a subclass withoutforwardcannot even be instantiated, andisinstanceis the only question the DSL asks. It was a correction: the bases were born as empty mixins that asked by duck typing whether the object had a method, and an object could get three different answers depending on which door it came in through. The names promised a contract nobody enforced.node()stays the lower door and accepts an outside object that inherits from nothing, because there the type is the caller’s to choose. Wiredoes not materialize untilsomatize. It records where you enter and where you leave, plus the lists of nodes and edges. That way joining two pieces is concatenating lists rather than merging two graphs, and a repeated id is caught at the end, once.- The DSL is nothing but
nodeandedge. There is a test that builds the same graph both ways and compares nodes, edges and plan.