Stuff about programming
Reactive Java.
Bookmark and Share

This post is about a thought experiment for what it would be like to program a reactive graphical user-interface in Java using the following abstractions:

Another side goal is to implement the automata with a variation of the state design-pattern i.e. using Java's anonymous inner classes to capture the local scope. The idea is to end up with a state machine that looks as much possible like a sequential program and not the typical fragments of code across separate state classes.

An event stream can be either an input event stream or an output event stream. Reactions to events on a stream are implemented with pub/sub i.e. the observer design pattern. An event stream is also an observable. An input event stream can be bound to a new output event stream, by adding an observer to the output stream, which notifies the input stream with streamed values. The class InputEventSream, shown just below, is a subject (observable) capable of receiving events of the generic type I. The bind method creates an output event stream that is capable of sending events of type I to the input stream that receives the bind method invocation. Bind takes a filter that converts the output values of type O to input values of type I. An identity filter can be used when no conversion is required. public class InputEventStream <I> implements Subject<I> { public void addObserver(Observer<I> o); public void notifyObservers(I v); public <O> OutputEventStream<O> bind(final EventStreamFilter<O,I> eventFilter); } Values are thus always sent on output event streams: public class OutputEventStream<O> implements Subject<O> { public void send(O v); }

A state machine is parameterised by the generic types I and O for the types of the input and output values for which the machine is capable of consuming and producing, respectively: class Machine<I, O> { protected InputEventStream<I> inputEventStream protected OutputEventStream<O> outputEventStream; private State<I> state; public void setState(State<I> h) { this.state = h; } public boolean update(I e) { return state.update(e); } } The machine processes an input event with a value of type I by delegating to the class State<I>. The state class processes the event and changes the state of the machine, through invoking the setState method. This is done using deeply nested anonymous inner classes. Thus, any states higher up within the lexical scope can be set as the current state, provided that they are declared with the final keyword-modifier. The machine produces output events of type O on its output event stream. A machine has typical accessors for its event streams, which are not shown here.

I have implemented a simple calculator using these machine and event stream classes. The calculator-machine's generic types I and O are instantiated with InputEnum and BigDecimal, respectively. That is, the calculator machine takes inputs that are digits, 0 to 9, operators ., +, -, /, *, commands = and C (for clear). The InputEnum class is a Java enum to enable pattern matching, Java style. The calculator machine produces BigDecimal output values.

Calculator

To integrate the state machine into a GUI, its input stream is simply bound to the buttons of the GUI and the output stream is bound to a text field for display. The complete code for the calculator and its supporting classes were coded up very quickly and so is work in progress but are available in my github repo for this post.

The unit test for the calculator machine, below, sends a stream of characters to the machine (converted into InputEnum's) and expects its computed result. (Note this test uses constants for demonstration only.) @Test public void runCalculator() { CalculatorMachine c = new CalculatorMachine(32); // display width 32 chars String input = "12.3+3.5+1.1*2="; for (int i = 0; i < input.length(); ++i) { c.update(InputEnum.map(input.charAt(i))); } Assert.assertEquals("33.8", c.getValue().toString()); }

My conclusions from this little programming experiment are:

blog comments powered by Disqus
Website created by Nicholas Nguyen.