FRP is based on two classes or data types. The example in chapter 1 used cell, and now we’re going to look at its counterpart, stream. Recall the following:
■ Cells—represent a value that changes over time
■ Streams—represent a stream of events Figure 2.1 shows an example: a window with a text field and a button. You can type text into the field, and when you click the button, the text field is cleared.
Figure 2.2 gives a conceptual view like the one we gave in chapter 1:
■ Arrows represent streams. They’re labeled with variable names.
■ Boxes represent transformations on streams. The label above a box
gives the name of the FRP operation being used. Arguments can appear in the center of the box.
■ Conceptual modules or black boxes are shown as clouds to indicate that their inter- nals have been obscured. They export or import streams or cells.
Three things happen when the user clicks the button:
1 An event is generated and fed into a stream named sClicked. Because a button click has no associated information other than the fact it happened, the event in sClicked contains a “nothing value” of a predefined type Unit. We’ll explain this type shortly.
NOTE The convention used in this book is to prefix the variable names of streams with s.
Figure 2.1 When you click Clear, the text you entered disappears.
Stream Operation Stream
Unit or
“nothing” value SButton
sClicked sClearIt
STextField
clear u text
Figure 2.2 Conceptual representation of the clearfield example
2 This event propagates to a map operation that transforms the Unit value into "", an empty string value. This map operation produces a new stream that we have called sClearIt.
NOTE If you’ve done any sort of functional programming before, you’ll have encountered the concept of map, but if not, don’t worry—we’ll go into more detail shortly. Don’t confuse map with the Java data structure Map that stores key/value pairs.
3 The event in sClearIt propagates to the text field and changes its text contents to the contained value, which is "". This is how the text field is cleared when the user clicks the button.
Recall from chapter 1 that Cell has a type parameter that you express with Java gener- ics to indicate the type of values contained in the cell. Stream also has a type parame- ter, telling you the type of the values propagated through the stream. The type of sClicked is Stream<Unit>, so the type of the values propagated by the stream is Unit.
Listing 2.1 gives the code, including all the Java stuff to make it work. Again, we’re using FRP-enhanced widgets from the toy SWidgets library.
NOTE If you want to experiment with the SWidgets library in your own code, you can install it into your local maven repository by going into the directory sodium/book/swidgets/java/swidgets and typing mvn install.
The Unit data type
Unit is a sort of “nothing value.” Unit is a term and concept from functional program- ming. Here’s why it’s useful.
In OOP programming, an event handler can take any number of arguments as needed.
Because a button click has no information associated with it other than the fact that it happened, you’d normally define a handler that takes no arguments, like this:
public void buttonClicked() { ... }
FRP is a little different. You can think of it as internally using event handlers that always take one argument. If there’s no value, you need a nothing value to plug the gap. Sodi- um defines a type Unit for this:
public enum Unit { UNIT };
In OOP style, the equivalent would be an imaginary one-argument event handler like this, although you don’t do this in FRP:
public void buttonClicked(Unit u) { ... }
The handler’s code would ignore u because it contains no information.
29 The Stream type: a stream of events
SButton is like a Swing JButton, but it exports an FRP stream that fires when the but- ton is clicked, through a public field declared like this:
public Stream<Unit> sClicked;
STextField is a text field with the following constructor:
STextField(Stream<String> sText, String initText)
You can pass it a stream in the first argument that can write text into the text field. It’s a simple matter to connect one to the other, but the types are different, so you need a map operation as we described to convert the Unit value to the empty string. The example is again using Java 8 lambda syntax here with map(), and we’ll go into more detail in a moment. Note how closely the code corresponds to the conceptual dia- gram.
import javax.swing.*;
import java.awt.FlowLayout;
import swidgets.*;
import nz.sodium.*;
public class clearfield {
public static void main(String[] args) { JFrame frame = new JFrame("clearfield");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
SButton clear = new SButton("Clear");
Stream<String> sClearIt = clear.sClicked.map(u -> "");
STextField text = new STextField(sClearIt, "Hello");
frame.add(text);
frame.add(clear);
frame.setSize(400, 160);
frame.setVisible(true);
} }
To run the example, check it out with git if you haven’t already done so, and then run it as follows:
git clone https://github.com/SodiumFRP/sodium cd sodium/book/swidgets/java
mvn test -Pclearfield or ant clearfield
We encourage you to tinker with the examples. If you’re using mvn, you can edit pom.xml to add your own build entries; for ant, edit build.xml.
DEFINITION Event—The propagation of an asynchronous message from one part of a program to another.
Listing 2.1 clearfield: a text field and a Clear button
Button with an FRP interface Maps the “button
clicked” stream to a stream of empty string events
Feeds sClearIt into STextField’s “write to text” input
DEFINITION Stream—A stream of discrete events. Also known in other FRP sys- tems as an event (in which case the things it contains are termed event occur- rences), an event stream, an observable, or a signal. When an event propagates through a stream, we sometimes say that the stream has fired.
Sodium defines a class called Stream for an FRP stream. The example uses Stream to represent button clicks. Here are some other examples of things it might make sense to model as streams:
■ Mouse clicks and touchscreen events
■ A monster being created or destroyed in a video game
■ A video game character receiving damage from a hit in a fight
■ A connection to a server being established or lost
■ Bookmarking a website in a browser
■ Adding, moving, or deleting a vertex in a polygon editor
■ Zeroing a trip-distance meter on a vehicle
When a stream fires, an event or a message is propagated from one part of the pro- gram to another. That message consists of a value, often referred to as a payload, and the type of that value is specified (in Java) using generics, in the same way you repre- sent the type of elements in a List or other container. For example, to represent a stream of keypress positions, you’d want the Stream to have a payload of type Char, so you’d declare it like this:
Stream<Char> sKeyPresses = ...
NOTE The examples in the next few chapters are in Java. We’ll give examples in some other languages later in the book. Look online for examples that have been translated to other programming languages.