Graph Procedure Composition
Great! Now Graph Procedures have given us free concurrency just by structuring our code declaratively rather than imperatively. But as we'd realistically only want to put a few nodes in a single Graph Procedure from a code maintenance and readability point of view, how do we write DAGS that are larger than just a few nodes? Composition! By this I mean simply calling another Graph Procedure from within the current one.
For Example:
Fig 1:
graph function bar(argB: int, argC: C) -> future<BarRes> {
root barRes <- doBar(@barA);
node barA <- doBarA(@barB, @barC);
node barB <- doBarB(argB);
node barC <- doBarC(argC);
}
graph TD
barC(barC) --> barA
barB(barB) --> barA
barA(barA) --> barRes
Fig 2:
graph function foo(argA: A) -> future<FooRes> {
root fooRes <- doFoo(@fooA, @fooB);
node fooA <- doFooA(@fooC);
node fooB <- bar(10, @fooC); # <-- Graph Composition via Call to `bar`.
node fooC <- doFooC(argA);
}
graph TD
fooC --> fooA
fooC --> fooB
fooB --> fooRes
fooA --> fooRes
Because foo(...) includes a call to bar(...) as a subgraph, you can imagine that node fooB in graph foo actually
composes around the entire bar graph.
graph TD
fooC --> fooA
fooC --> barC
barRes --> fooRes
subgraph fooB
barC --> barA
barB --> barA
barA --> barRes
end
fooA --> fooRes
This composition is extremely simple to understand in this way. The entire subgraph is started after all data dependencies of the node wrapping it are ready.