Graph clause

The graph clause of a composite operator describes a stream data flow subgraph, which can then be expanded in different contexts when the operator is invoked.

Here is an example of the graph clause:

 composite M (output K, L; input G, H) {
   graph stream<int32 x> I = Functor(G)   { /*..O..*/ }
         stream<int32 x> J = Functor(H)   { /*..P..*/ }
         stream<int32 x> K = Custom(I; J) { /*..Q..*/ }
         stream<int32 x> L = Functor(J)   { /*..R..*/ }
 }
 composite Main {
   graph stream<int32 x> A = Beacon() {}
         stream<int32 x> B = Beacon() {}
         (stream<int32 x> C; stream<int32 x> D) = M(A; B) { }
         (stream<int32 x> E; stream<int32 x> F) = M(A; B) { }
 }
Figure 1. Composite operator expansion example
This figure is described in the surrounding text.

The figure illustrates the graph topology in this example. The original graph contains two invocations using composite operator M: once to transform A and B into C and D, and the other time to transform A and B into E and F. The head of the composite operator definition (output K, L; input G, H) defines input and output ports. When the composite operator gets used, actual input and output streams are bound to these ports; for example, for the first invocation, the bindings are G=A, H=B, K=C, and L=D. In the expanded graph, intermediate streams such as I and J in the example are duplicated and renamed C.I, C.J, E.I, and E.J.

Note: The compile-time expansion of composite operators behaves similarly to macros, but is "hygienic", since it generates new names to prevent unintended name capture.