Getting started
The best way to learn a new programming language is to write programs in it. But to write programs, you need to know how to compile and run programs because you frequently want to test whether what you wrote does what you expect.
This tutorial starts with a simple program, whose purpose is less to illustrate the language features than to try working with the compiler. Here is the code:
composite HelloWorld {
graph
stream<rstring message> Hi = Beacon() {
param iterations : 1u;
output Hi : message = "Hello, world!";
}
() as Sink = Custom(Hi) {
logic onTuple Hi : printStringLn(message);
}
}
First, focus on getting the program that is compiled and defer the description on how the code works. You get the most out of this tutorial if you try out things as you go along. Therefore, the tutorial frequently has information like the following instructions: make sure that you use a computer on which Teracloud® Streams is installed, and the SPL compiler that is named sc is available. Create a directory that is called HelloWorld on that computer. Create a file in the directory that is called HelloWorld.spl. Enter the sample program text, and then save it. Make sure that you are in that directory, and run the compiler, by entering the following command:
sc -M HelloWorld
This command creates a stand-alone executable file, that is, a program that can run as a single process on a single computer, without requiring a running Teracloud® Streams instance. The -M HelloWorld command-line option specifies that the main composite is called HelloWorld. Each SPL program has one main composite operator. A composite operator is an operator that encapsulates a stream graph, and the stream graph of a main composite can be run as a program. If you ran the compiler as described, and there were no compiler errors, then it created the executable file ./output/bin/standalone. Run the executable file. It prints Hello, world! to the console.
Second, focus on how the code works. Line 1 declares a composite
operator: composite HelloWorld { ... }
. Line 2 starts
a graph clause, which means that Lines 3-9 describe a stream graph.
The graph consists of two operator invocations. Line 3 is the head
of the first operator invocation: stream<rstring message>
Hi = Beacon()
invokes operator Beacon to
produce a stream Hi
whose tuples have one attribute rstring
message
. Line 7 is the head of the second operator invocation: ()
as Sink = Custom(Hi)
invokes operator Custom,
which reads from stream Hi
. The () as Sink
part
indicates that this operator invocation produces no stream ((
)
), and has the name Sink. Here is a visual
representation of this stream graph:

The operator invocations are shown as circles, and the stream is
shown as an arrow. The operator invocations are decorated at the lower
right with little scratch-paper icons that indicate internal state:
both Beacon and Sink are stateful
in this program. The Beacon operator produces data. In
this invocation, Line 4, param iterations : 1u;
,
tells it to produce just one tuple; the u
suffix
on the number 1
makes it an unsigned integer, since
it would not make sense to have a negative number of iterations. In
SPL, users or library writers define operators (like Beacon)
and their parameters (like iterations
) using a common
framework; they are not built into the language. Line 5, output
Hi : message = "Hello, world!";
, assigns the string "Hello,
world!" to attribute message
of output
stream Hi. Moving on to the second operator
invocation, the Custom operator provides a clean
slate for custom user logic. Line 8, logic onTuple Hi : printStringLn(message)
,
specifies that upon arrival of a tuple on stream Hi
,
the program prints the string attribute message
from
the tuple, followed by a newline character \n
.
At this point, you compiled and run a first SPL program, and you understand what it does. This program illustrates only a tiny fraction of SPL, but before you move on to more interesting examples, here is a look at the compiled code. Besides the stand-alone executable file, the compiler also generated several other artifacts. Recall that this example started out from just one directory HelloWorld and with just one file HelloWorld.spl. If you look at the directory after you compile, you will find something like the following structure:
/+ HelloWorld
/+ HelloWorld.spl # SPL source code
/* toolkit.xml # toolkit index
/* data # directory for data read/written by the program
/* output # directory for artifacts generated by the compiler
/* HelloWorld.sab # application bundle file
/* HelloWorld.adl # ADL (application description language) file
/* bin # compiled binaries
/* standalone # the standalone executable from earlier
/* src # generated C++ source code
/* operator # source code for operator invocations
/* pe # source code for PEs (processing elements)
/* standalone # source code for the standalone file
/* type # source code for types
In this listing, authored files (files that are written by hand) are annotated with /+ and generated files (files that are written automatically by the compiler) are annotated with /*. For now, all the generated artifacts are not covered in detail, but you are encouraged to look at a few of them to get a feeling for what they look like.
The purpose of this tutorial is to provide an introduction to SPL. To
focus on the essentials, it intentionally omits details that you do
not immediately need to know, but can look up at your leisure in the
reference documentation. This example gives an example for using the sc command,
the SPL compiler. For more information about using the SPL compiler,
see the Compiler documentation. This example also uses
the toolkit operators Beacon and Custom,
and the toolkit function printString
. For more information
about library operators and functions, see the SPL standard toolkit
documentation.