diff --git a/docs/framework_concepts/building_graphs_cpp.md b/docs/framework_concepts/building_graphs_cpp.md index 29d0c25d5..49ee52991 100644 --- a/docs/framework_concepts/building_graphs_cpp.md +++ b/docs/framework_concepts/building_graphs_cpp.md @@ -275,3 +275,69 @@ Tip: the same as for the `RunInference` function, extracting `PassThroughNodeBuilder` and similar utility classes into dedicated modules enables reuse in graph construction code and helps to automatically pull in the corresponding calculator dependencies. + +## Dos and Don'ts + +### Define graph inputs at the very beginning if possible + +```c++ {.bad} +Stream RunSomething(Stream a, Stream b, Graph& graph) { + Stream c = graph.In(2).SetName("c").Cast(); // Bad. + // ... +} + +CalculatorGraphConfig BuildGraph() { + Graph graph; + + Stream a = graph.In(0).SetName("a").Cast(); + // 10/100/N lines of code. + Stream b = graph.In(1).SetName("b").Cast() // Bad. + Stream d = RunSomething(a, b, graph); + // ... +} + +``` + +In the above code: + +* It can be hard to guess how many inputs you have in the graph. +* Can be error prone overall and hard to maintain in future (e.g. is it a + correct index? name? what if some inputs are removed or made optional? + etc.). + +Instead, simply define your graph inputs at the very beginning of your graph +builder: + +```c++ {.good} +Stream RunSomething(Stream a, Stream b, Stream c, Graph& graph) { + // ... +} + +CalculatorGraphConfig BuildGraph() { + Graph graph; + + Stream a = graph.In(0).SetName("a").Cast(); + Stream b = graph.In(1).SetName("b").Cast(); + Stream c = graph.In(2).SetName("c").Cast(); + + // 10/100/N lines of code. + Stream d = RunSomething(a, b, c, graph); + // ... +} +``` + +And if you have an input stream or side packet that is not always defined - +simply use `std::optional` and put it at the very beginning as well: + +```c++ {.good} +std::optional> a; +if (needs_a) { + a = graph.In(0).SetName(a).Cast(); +} +``` + +Note: of course, there can be exceptions - for example, there can be a use case +where calling `RunSomething1(..., graph)`, ..., `RunSomethingN(..., graph)` is +**intended to add new inputs**, so afterwards you can iterate over them and feed +only added inputs into the graph. However, in any case, try to make it easy for +readers to find out what graph inputs it has or may have.