Operator invocation head

The head of an operator invocation lists the output and input streams and the name of the operator that processes the data.

Figure 1. Graphical representation of the information in an operator invocation head

This figure shows a contrived operator invocation that illustrates multiple output and input stream and aliases.

All the other information that pertains to the operator invocation is in the operator invocation body, making it possible for users to quickly scan a program's topology. The following SPL code is an example of the more advanced features of operator invocation heads:

composite Main {
  graph
    stream<list<int32> n, float64 i> SomeLongNameForAnInputStream = Beacon() {}
    stream<float64 i> FirstStreamInSecondPort = Beacon() {}
    stream<FirstStreamInSecondPort> SecondStreamInSecondPort = Beacon() {}
    ( stream<int32 a1, int32 a2> SomeLongNameForAnOutputStream as A;
      stream<float64 b> AnotherLongNameForAnOutputStream as B
    ) = MyOperator(
      SomeLongNameForAnInputStream as C;
      stream<float64 i> FirstStreamInSecondPort, SecondStreamInSecondPort as D
    ) {
        output A: a1=1, a2=max(n);
               B: b = C.i + D.i;
    }
}
Lines 6 and 7 show the two output streams that are defined by this operator invocation. The output streams are separated by a semicolon. Each has a type, a name, and an optional alias (as A and as B). The type lists the attributes of tuples on the stream; the name can be used as input to other operator invocations; and the alias can be used internally in this stream's body. Line 8 of the example shows the name of the operator to invoke, in this case, MyOperator. Finally, Lines 9 and 10 show two input ports, which are separated by a semicolon. Each has an optional type, one or more stream names that are separated by commas, and an optional alias (as C and as D). Port D combines two input streams, FirstStreamInSecondPort and SecondStreamInSecondPort, separated by commas. The general syntax is:
opInvokeHead ::= opOutputs ( 'as' ID )? '=' ID opInputs
opOutputs    ::= opOutput | '(' opOutput*; ‘)'
opOutput     ::= streamTypeID ( ‘as' ID )?
opInputs     ::= '(' portInputs*; ')'
portInputs   ::= streamType? ID+, ( 'as' ID )?

A port is a point at which streams connect to an operator invocation. The figure shows ports as little triangles. Each output port produces exactly one output stream, but an input port can combine more than one input stream. When there is exactly one output port, the parentheses around the outputs can be omitted.

The syntax allows as-clauses in three places. The top-level as-clause gives an operator instance name; an as-clause on an output port gives an output port alias; and an as-clause on an input port gives an input port alias. When there are zero output ports, the empty parentheses and the top-level as-clause with the operator instance name are mandatory, for example, () as A = B(). The as-clauses with port aliases, however, are always optional, and are useful to make the operator invocation body more readable by providing a local short name.

Types on input streams are redundant because they also occur when those streams are defined as outputs of other operator invocations. Nevertheless, you can optionally specify these types when you feel that they make code more readable. This specification can also lead to more understandable compiler error messages when there is a type mismatch. When there are multiple streams on the same input port, tuples that are coming from different streams are interleaved. The order of the interleaving is non-deterministic in the sense that no particular order is imposed by the run time.

Output ports carry a mandatory stream type, and input ports carry an optional stream type. A stream type just consists of a tuple body:
streamType ::= 'stream' '<' tupleBody '>'

If there are multiple input streams on the same port, they must all have the same type. If the type of an input port is explicitly specified, it must be equivalent to the type of the streams that are connecting to it. The tupleBody component of the stream type can be either a list of attributes, or a list of tuple types (extension), where identifiers can refer to types of other streams by their stream names. For details, see Tuples.

Tip: Instead of using the as alias notation, use short stream names in the first place. Stream names that are too long indicate that it might be time to decompose the program into composite operators. For more information, see Composite operators.