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
    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.